本节内容: 10.2.1: 数组
10.2.2: 向量
10.2.3: 列表
10.2.4: GenericStack
10.2.5: Map
10.2.6: Option
一个数组是一个元素的集合。它有一个类型参数(第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.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 来详细了解向量方法。
列表是一个存储的元素的集合。从表面上看,一个列表类似于一个数组。然而,潜在的实现非常不同。这体现在一些功能差异:
- 列表不能被使用方括号索引,即 [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 详细了解列表方法。
一个 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 详细了解它的方法。
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 详细了解它的方法。
一个 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");
}
}
}