Array 是存储值列表的主要类型,提供最简单的方法来添加和提取其中的值。Haxe 数组的多数语法和 Java、ActionScript 中的很相似,所以开发者如果了解这些语言,可以快速的阅读本节,了解一些主要的区别。
Haxe 中使用 Array 之前,必须先实例化,除非你使用字面值初始化 Array 列表。对于本章目的,只需要使用 `new Array() ` 赋值到 Array 类型变量即可:
~~~
var myArray : Array < Int > = new Array();
~~~
不需要在实例化的时候重新制定包含的数据类型,事实上,任何添加到第二个 Array 关键字的类型标识符都会被丢弃。
可以通过重新实例化它来清空一个数组的数据。然而,为了关联改变一个数组里数据类型,一个新的数组对象需要被声明并实例化。
一旦实例化了Array对象,可以使用数据进行填充和使用它们。表显示了操作Array的一些可用方法:
|数组字段|描述|
| -- | -- |
|length: Int|返回当前项的数量。length 是一个只读属性|
|concat(a: Array<T>): Array<T>|连接一个数组到当前数组对象的尾部,不改变原数组,返回一个新的数组|
|copy():Array<T>|返回一个新的数组结构,包含相同的布局和数据|
|insert(pos: Int, x:T): Void|添加数据到数组的任何位置|
|iterator(): Iterator<Null<T>>|返回数组值的一个迭代器|
|join(sep: String): String|返回一个字符串,包含了通过一个指定分隔符连接的所有数组项|
|pop():Null<T>|删除原数组最后一个元素并返回该元素,直接在原数组操作|
|push(x:T):Int|添加指定的项到数组结尾并返回它的位置,直接在原数组操作|
|remove(x:T):Bool|移除第一次出现的指定匹配项,返回一个布尔值结果,成功为true,未找到项为false|
|shitf(): Null<T>|删除数组中第一个项,并返回它,操作原数组|
|slice(pos: Int, ?end: Int):Array<T>|拷贝指定范围的数组,返回一个新的数组|
|sort(f:T->T->Int): Void|根据指定的比对函数排序数组,函数如果x==y则返回0,x>y则返回值大于0,x<y则返回值小于0|
|splice(pos: Int, len: Int):Array<T>|移除指定范围的项,返回它们为一个新的数组|
|toString(): String|返回数组的字符串表现形式|
|unshift(x:T):Void|添加指定的项到数组开始|
`T` 类型本身不是一个类型,但是是一个占位符,代表在运行时决定类型,以符合强类型,当剩下的任何你希望传入函数的匿名结构。T 类型在以后详加介绍。
# 从Array中添加或者移除项
* * * * *
有很多方式添加和移除项。每个方法提供某个特定角度的操作。从开始,从尾部,或者数组的任意位置。如果你知道项的定位,可以指定这个位置直接修改为任何变量。通过 索引操作符([])实现这个:
~~~
myArray[3] = 44;
var myInt = myArray[3];
~~~
这里,索引位置为3,代表Array里第4个项,设置其值为 44, 然后同样的值传递到变量 myInt。 当然,如果第4个项已经包含一个你不想覆盖的值这会是一个问题。这种情况,可以使用Array的lenght属性,它会返回数组的长度:
~~~
var numItemsInArray : Int = myArray.length;
myArray[numItemsInArray] = 44;
~~~
数组中的项从0开始,Array的lenght是数组下一个可用的空间。这就是说,不论指定多长,使用length属性作为新的索引永远不会覆盖存在的值。
# Pushing 和 popping值
* * * * *
另一个方式执行相同的技巧是使用 push 方法。这个方法确保添加到Array中的值只会附加到Array的尾部。
~~~
var lastLocation : Int = myArray.push(44);
~~~
push 方法返回最后添加的值的位置,可以使用来操作该值。同样的方式,可以使用 pop 方法移除最后一个项:
~~~
var poppedValue : Int = myArray.pop();
~~~
一旦删除最后一个项,方法会放回被删除的值而不是忽略它。以备你可能需要对他进行某种处理。
# Shifting 和 Unshifting 值
* * * * *
Haxe数组也提供一个手段来添加值到Array的头部,可以使用 unshift方法:
~~~
myArray.unshift(44);
~~~
unshift 方法和push 方法表现方式相同,除了返回 Void ,而不是返回位置之外。这是因为新增的项索引总是为0。当添加值到Array 的开头,所有其他的值会下移一个顺序,所以添加之前第一项的索引会变成 1 。
相似的 pop 方法用来移除数据,返回Array头部的数据:
~~~
var shiftedValue : Int = myArray.shift();
~~~
# 从Array中间添加或者移除数据
* * * * *
两个主要的方法用于从Array中间移除数据分别是 remove 和splice 。两个方法都执行项的移除,但是以不同的方式,都非常有用。
## remove()
remove 方法用来寻找并删除一个项,通过制定的值。这个方法只接受一个参数,匹配的将被删除的值。从Array的开始起,这个方法搜索指定的值,当它找到了,搜索便会停止,值将被删除,使所有的它之后的项提升1个位置:
~~~
var isFound : Bool = myArray.remove(4);
~~~
remove 方法如果删除成功则返回 true,如果没有匹配则返回false。因此,它可以用来重复搜索,如果需要,直到返回 false ,所有指定的值都会被删除。
## Splice()
splice 方法可以移除多个项。splice 接受两个参数,开始位置和要移除的项的数量:
~~~
var chunk : Array < Int > = myArray.splice(2,2);
~~~
一旦移除成功,一块的项会被返回,你可以存储它到一个新的Array,如果你希望的话。
还可以指定开始位置从尾部开始,使用一个负数。这种情况, -1 表示最后一个项,而递减的往回数Array的项列表:
~~~
var chunk : Array < Int > = myArray.splice(-2,2);
~~~
这里,最后两个项被移除然后存储到Array变量 chunk 。
## 使用insert()插入值
插入一个值到Array的中间可以使用简单的 insert 方法。 insert 接受两个参数,添加值得为之,和希望插入的值。一旦插入了之,所有存在的在其之后的项位置都会后移1 个:
~~~
myArray.insert(4, someValue);
~~~
# 拷贝和连接数组
* * * * *
数组是对象,并不是Haxe的基础类型 list 。所以,从一个变量传递一个 Array 到另一个不会创建一个数组的副本,仅仅是创建两个变量,然后指向相同的内存信息。这意味着修改一个Array会自动的修改另一个Array。现在并不需要太深入理解,因为这是其他章节的话题,但是需要说的是,如果你希望复制一个Array的结构到另一个新的Array,需要一些帮助。幸好Haxe提供了一些工具来做这件事,使用 slice 和copy 封装。
## slice()
slice 方法接受两个参数,返回Array的一个块,看起来工作方式和 splice 非常接近。不得不承认经常混淆 slice 和splice之间的用法。两者听起来都像血淋林的恐怖电影(切割),如果使用 splice 表示你保护Array中的数据将其留下。
两者之间有一个差别,然而如果有时错误的时候可能会抛出一个编译器的错误,但至少会让你明白二者的差别。splice 需要 第二个参数指定你要拷贝的块的结尾位置。这个终点位置不包含在拷贝块之内。
像 splice一样,你可以使用一个负数作为开始位置,但是也可食用一个负数作为块的结尾。记住,开始位置必须在结束为止之前出现:
~~~
var arrayCpy : Array < Int > = myArray.slice(-4,-2);
~~~
## copy()
copy 方法应用到整个数组,创建一个精确的副本,不需要参数:
~~~
var arrayCpy : Array < Int > = myArray.copy();
~~~
警告一下, copy 和slice 方法不会创建重复的数据。因此,如果你的原数组包含对象,拷贝Array的数据会包含这些对象的引用,而不是副本。
现在你可以拷贝Array,怎么拷贝一个Array到另外一个数组的尾部?这操作叫做连接,可以使用 concat 方法对Array进行连接。
## concat()
concat 方法拷贝指定Array的结构到调用方法的Array。要连接的数组的项不会重复,但是通过引用传递,所以这不是一个问题,如果只是基础类型如 Int 或者 String :
~~~
myArray.concat(newArray);
~~~
# 多维数组
* * * * *
多维数组,提供Haxe里非常有用的功能。听起来就像矩阵,多维数组可以帮助我们处理数组的组,或者数组的组的组,可以想象这个。
要更好的理解多维数组,想象它们用于数字。例如,一千包含十个一百,一百包含十个十,十包含是个单位。可以将其作为Array格式,通过放置每四个数值组之一到 Arrays,就像这样:
~~~
var thousandths : Array < Int > = [0,1,2,3,4,5,6,7,8,9];
var hundredths : Array < Int > = [0,1,2,3,4,5,6,7,8,9];
var tens : Array < Int > = [0,1,2,3,4,5,6,7,8,9];
var units : Array < Int > = [0,1,2,3,4,5,6,7,8,9];
~~~
这个方法的问题是组保存在每个数组并没有连接起来。你只有每个Array类型之一,理论上讲,应该有是个千位数组,一百个百位数组,一千个十位数组,一万个个位数组。更多的是,每个数组需要关联到父数组的关联项。
要解决这个问题,可以创建数组的数组,通过指定父数组的类型为数组,然后依次重复这个操作为每个层次:
~~~
var numbers : Array < Array < Array < Array < Int > > > > ;
~~~
一旦这样做,你需要实例化每个数组的层次结构:
~~~
numbers = new Array();
for ( a = 0...9 )
{
numbers[a] = new Array();
for ( b = 0...9 )
{
numbers[a][b] = new Array();
for ( c = 0...9 )
{
numbers[a][b][c] = new Array();
for ( d = 0...9 )
numbers[a][b][c][d] = ( a * 1000 ) + ( b * 100 ) + ( c * 10 ) + d;
}
}
}
~~~
这回继续下去直到实例化完所有的层次结构中的数字,虽然你可以有选择的做这些,而不是所有都在前面。一旦这样做了,你可以访问数组通过提供一个index操作符的对来访问数组:
~~~
var thousands : Int = 6;
var hundreds : Int = 4;
var tens : Int = 7;
var units : Int = 3;
numbers[thousands][hundreds][tens][units] = 6473;
~~~
或者:
~~~
numbers[6][4][7][3] = 6473;
~~~
理论上说,一个多维数组可以有许多尽可能大的尺寸,然而很少使用同时超过2维的数组。
- 本书目录
- 第一章:Haxe介绍
- 互联网开发的一个问题
- Haxe是什么,为什么产生
- Haxe编译工具
- Haxe语言
- Haxe如何工作
- 那么Neko是什么
- Haxe和Neko的必须条件
- 本章摘要
- 第二章:安装、使用Haxe和Neko
- 安装Haxe
- 使用Haxe安装程序
- 在Windows上手动安装Haxe
- Linux上手动安装Haxe
- 安装Neko
- Windows上手动安装Neko
- 在Linux上安装Neko
- Hello world! 一式三份
- 编译你的第一个Haxe应用
- 你的程序如何编译
- HXML编译文件
- 编译到Neko
- 编译为JavaScript
- 程序结构
- 编译工具开关
- 本章摘要
- 第三章:基础知识学习
- Haxe层级结构
- 标准数据类型
- 变量
- 类型推断
- 常数变量
- 简单的值类型
- 浮点类型
- 整型
- 选择数值类型
- 布尔类型
- 字符串类型
- 抽象类型
- Void 和 Null
- 动态类型
- unknown类型
- 使用untyped绕过静态类型
- 注释代码
- 转换数据类型
- Haxe数组
- Array
- List
- Map
- Haxe中使用日期时间
- 创建一个时间对象
- Date组件
- DateTools类
- 操作数据
- 操作符
- Math类
- 使用String函数
- 本章摘要
- 第四章:信息流控制
- 数据存放之外
- 条件语句
- if语句
- switch语句
- 从条件语句返回值
- 循环
- while循环
- for循环
- 循环集合
- Break和Continue
- 函数
- 类的函数
- 局部函数
- Lambda类
- 本章摘要
- 第五章:深入面向对象编程
- 类和对象
- 实例字段
- 静态字段
- 理解继承
- Super
- 函数重载
- 构造器重载
- toString()
- 抽象类和抽象方法
- 静态字段,实例变量和继承
- 继承规则
- 使用接口
- 高级类和对象特性
- 类的实现
- 类型参数
- 匿名对象
- 实现动态
- Typedef
- 扩展
- 枚举
- 构造器参数
- 本章摘要
- 第六章:组织你的代码
- 编写可重用代码
- 使用包
- 声明一个包
- 隐式导入
- 显式导入
- 枚举和包
- 类型查找顺序
- 导入一个完整的包
- 导入库
- Haxe标准库
- Haxelib库
- 其他项目中的库
- 外部库
- 使用资源
- 文档化代码
- 离线文档
- 在线文档
- 单元测试
- haxe.unit包
- 编写测试
- 本章摘要
- 第七章:错误调试
- trace函数
- trace输出
- haxe的trace和ActionScript的trace
- 异常
- 异常处理
- CallStack和ExceptionStack
- 异常管理类
- 创建完全的异常处理类
- 异常类代码
- 本章摘要
- 第八章:跨平台工具
- XML
- XML剖析
- Haxe XML API
- 正则表达式
- EReg类
- 模式
- 定时器
- 延迟动作
- 队列动作
- MD5
- 本章摘要
- 第九章:使用Haxe构建网站
- Web开发介绍
- Web 服务器
- 使用Web服务器发布内容
- HTML速成课程
- Haxe和HTML的区别
- NekoTools Web Server
- Apache安装mod_neko
- Windows安装Apache和mod_neko
- Linux安装Apache和Mod_Neko
- 第一个Haxe网站
- 使用Neko作为网页Controller
- neko.Web类
- Neko作为前端控制器
- 本章摘要
- 第十章:使用模板进行分离式设计
- 什么是模板
- Template类
- Template语法
- 使用资产
- 何时在模板中使用代码
- 服务器端模板的Templo
- 安装Templo
- 使用Templo
- haxe.Template和mtwin.Templo表达式上的区别
- Attr表达式
- Raw表达式
- 逻辑表达式
- 循环表达式
- set, fill, 和 use表达式
- Templo中使用宏
- 手动编译模版
- 第十一章:执行服务端技巧
- 第十二章:使用Flash构建交互内容
- 第十三章:使用IDE
- 第十四章:通过JavaScript制作更多交互内容
- 第十五章:通过Haxe远程通信连接所学
- 第十六章:Haxe高级话题
- 第十七章:Neko开发桌面应用
- 第十八章:用SWHX开发桌面Flash
- 第十九章:多媒体和Neko
- 第二十章:使用C/C++扩展Haxe
- 附加部分