Skip to content

Latest commit

 

History

History
282 lines (207 loc) · 7.96 KB

10.2.数据结构.md

File metadata and controls

282 lines (207 loc) · 7.96 KB

10.2.数据结构

本节内容: 10.2.1: 数组

10.2.2: 向量

10.2.3: 列表

10.2.4: GenericStack

10.2.5: Map

10.2.6: Option

10.2.1.数组

一个数组是一个元素的集合。它有一个类型参数(第3.2节),对应这些元素的类型。数组可以被通过以下三种方式创建:

  • 使用它们的构造函数 : new Array()
  • 使用数组声明语法(第5.5节) : [1, 2, 3]
  • 使用数组推导(第6.6节) : [for (i in 0...10) if ( i % 2 == 0 ) i]

数组附带一个 API ,覆盖了多数的用例。另外,它们允许读/写 的数组访问(第5.8节):

class Main { 
    static public function main() { 
        var a = [1, 2, 3]; 
        trace(a[1]); // 2 
        a[1] = 1; 
        trace(a[1]); // 1 
    } 
}

由于 Haxe 中的数组访问是没有边界的,即,数组保证不会抛出异常,这需要进一步讨论:

  • 如果对一个不存在的索引做出一个读访问,将根据目标语言返回一个值。
  • 如果对一个越界的正索引做出一个写访问,则在最后有定义的索引与这个新写入的索引项之间的所有位置插入null(或者静态目标语言(第2.2节)中基本类型(第2.1节)的默认值(第2.2节))。
  • 如果使用一个负索引写访问,结果是未指定的。

数组在它的元素之上定义了一个迭代器(第6.7节)。这个迭代通常由编译器优化后以一个 while 循环(第5.14节)配合数组下标进行:

class Main { 
    static public function main() { 
        var scores = [110, 170, 35];
        var sum = 0; 
        for (score in scores) { 
            sum += score; 
        } 
        trace(sum); // 315
    }
} 

Haxe 生成这个优化后的 JavaScript 输出:

 Main.main = function() { 
    var scores = [110,170,35]; 
    var sum = 0; 
    var _g = 0; 
    while(_g < scores.length) { 
        var score = scores[_g]; 
        ++_g; 
        sum += score; 
    }
    console.log(sum); 
};

Haxe 不允许混合类型的数组,除非参数类型被限强制为 Dynamic(第2.7节):

class Main { 
    static public function main() { 
        // Compile Error: Arrays of mixed types are only allowed if the type is 
        // forced to Array<Dynamic> 
        //var myArray = [10, "Bob", false];
        
        // Array<Dynamic> with mixed types 
        var myExplicitArray:Array<Dynamic> = [10, "Sally", true];
    } 
}

花絮: 动态数组 在Haxe 2中,混合类型的数组声明是被允许的。在Haxe 3中,数组只有显式声明为 Array 才可以为混合类型。

查看数组API了解它的方法的详细内容。

10.2.2.向量

一个向量是一个优化的固定长度的元素集合。很像数组(第10.2.1节),它只有一种类型参数(第3.2节),所有向量的元素必须是特定类型,可以使用一个 for 循环(第5.13节)迭代,并使用数组访问(第2.8.3节)的语法访问。然而,不像数组和立标,向量长度是被创建时指定的,并且之后不能被修改。

class Main { 
    static function main() { 
        var vec = new haxe.ds.Vector(10); 
        
        for (i in 0...vec.length) { 
            vec[i] = i; 
        } 
        
        trace(vec[0]); // 0 
        trace(vec[5]); // 5 
        trace(vec[9]); // 9 
    } 
}

haxe.ds.Vector 被实现为一个抽象类型(Abstract)(第2.8节),在给定目标语言的原生数组实现之上,是更快速的固定长度的集合,因为存储它的元素的内存被预分配了。

查看Vector API 来详细了解向量方法。

10.2.3.列表

列表是一个存储的元素的集合。从表面上看,一个列表类似于一个数组。然而,潜在的实现非常不同。这体现在一些功能差异:

  • 列表不能被使用方括号索引,即 [0] 形式。
  • 列表不能被初始化。
  • 没有列表推导。
  • 列表在迭代的时候可以自由修改和删除元素。

使用列表的一个简单例子:

class Main { 
    static public function main() {
        var myList = new List<Int>(); 
        for (ii in 0...5) 
            myList.add(ii);
        trace(myList); //{0, 1, 2, 3, 4}
    }
} 

查看List API 详细了解列表方法。

10.2.4.GenericStack

一个 GenericStack,就像数组和列表,是一个存储元素的容器。它有一个类型参数(第3.2节),这个堆栈的所有元素必须是特定类型。这里有一个初始化和使用GenericStack的小示例程序。

import haxe.ds.GenericStack;

class Main {
    static public function main() {
        var myStack = new GenericStack<Int>(); 
        for (ii in 0...5) 
            myStack.add(ii); 
        trace(myStack); //{4, 3, 2, 1, 0} 
        trace(myStack.pop()); //4 
    } 
}

花絮: FastList 在Haxe 2中, GenericStack类被称为 FastList 。由于它的行为非常接近传统的堆栈,所以在Haxe 3中修改了名字。

GenericStack 中的 Generic 是字面的。它被通过 :generic 元数据归结。根据目标语言,这可以提升静态目标语言的性能。查看 Generic(第3.3节)了解详细内容。

查看GenericStack API 详细了解它的方法。

10.2.5.Map

Map 是一个键值对组成的容器。一个 Map 也通常被称为一个关联数组、字典或者符号表。下面的代码是要给简短的使用Map的示例:

class Main { 
    static public function main() { 
        // Maps are initialized like arrays, but 
        // use the map literal syntax with the 
        // ’=>’ operator. Maps can have their 
        // key value types defined explicity 
        var map1:Map<Int, String> = 
        [1 => "one", 2=>"two"]; 
        
        // Or they can infer their key value types 
        var map2 = [ 
            "one"=>1, 
            "two"=>2,
            "three"=>3 
        ]; 
        $type(map2); // Map<String, Int> 
        
        // Keys must be unique 
        // Error: Duplicate Key 
        //var map3 = [1=>"dog", 1=>"cat"]; 
        
        // Maps values can be accessed using array 
        // accessors "[]" 
        var map4 = ["M"=>"Monday", "T"=>"Tuesday"]; 
        trace(map4["M"]); //Monday 
        
        // Maps iterate over their values by 
        // default 
        var valueSum; 
        for (value in map4) { 
            trace(value); // Monday \n Tuesday 
        } 
        
        // Can iterate over keys by using the
        // keys() method 
        for (key in map4.keys()) { 
            trace(key); // M \n T 
        } 
        
        // Like arrays, a new Map can be made using 
        // comprehension 
        var map5 = [
            for (key in map4.keys()) 
                key => "FRIDAY!!" 
        ]; 
        // {M => FRIDAY!!, T => FRIDAY!!} 
        trace(map5); 
    } 
} 

在后台,Map 是一个抽象类型。在编译时,它被转换为集中特定类型之一,取决于键的类型:

  • String : haxe.ds.StringMap
  • Int : haxe.ds.IntMap
  • EnumValue : haxe.ds.EnumValueMap
  • {} : haxe.ds.ObjectMap

Map类型在运行时不存在,被上面的对象之一取代。Map使用它的键类型定义数组访问(第2.8.3节)。

查看Map API 详细了解它的方法。

10.2.6.Option

一个 Option 是Haxe标准库中的一个枚举,如下形式定义:

enum Option<T> { 
    Some(v:T); 
    None; 
} 

它可以被使用在各种各样的状况,比如 沟通一个方法是否有一个有效的返回,如果是的话,它返回什么值:

import haxe.ds.Option; 

class Main { 
    static public function main() { 
        var result = trySomething();
        switch (result) { 
            case None:
                trace("Got None"); 
            case Some(s): 
                trace("Got a value: " +s); 
        } 
    } 
    
    static function trySomething():Option<String> { 
        if (Math.random() > 0.5) { 
            return None; 
        } else { 
            return Some("Success"); 
        }
    }
}