一些类或接口是特定操作其他类的实例。这些操作可以被在不分享任何通用父类或接口类的实例执行。考虑如下例子:
~~~
class BinaryNode
{
private var content : String;
public var parent : BinaryNode;
public var leftChild : BinaryNode;
public var rightChild : BinaryNode;
public function new (content : String)
{
this.content = content;
}
public function getContent() : String
{
return content;
}
}
~~~
BinaryNode 类是一个非常简单的容器来层级结构存储信息。这个例子,每个节点的内容是String类型,但是它听起来很显然,完全相同的 node 类可以简单的被改变来存储任何类型的值。要这样做使用至今获得的只是,问题可以以两种方式之一解决:声明一个新的 node 类对每个存储到它的类型或者使用一个 Dynamic类型的内容。第一种方案非常重复(记住DRY原则,don't repeat yourself),而且当实现只有一点改变的时候非常痛苦。第二个方案是脆弱的因为它需要不断地投射到一个合适的类型每次 getContent() 被调用时,并且总是一个好的实践来避免不安全的投射如果不是绝对必要。
需要的是一个通用的方法(generics是用在C#和JAVA等语言中同样上下文的术语);这完全就是所用的类型参数的目的。一个类型参数是一个通用的具体类型的占位符。
重新编码,按照如下:
~~~
class BinaryNode < T >
{
private var content : T;
public var parent : BinaryNode < T > ;
public var leftChild : BinaryNode < T > ;
public var rightChild : BinaryNode < T > ;
public function new (content : T)
{
this.content = content;
}
public function getContent() : T
{
return content;
}
}
~~~
在类的实例化中一个类型必须提供 T 按照如下方式:
~~~
var ns : BinaryNode < String > = new BinaryNode < String > (“I’m a node”);
~~~
另一个例子是:
~~~
var ni : BinaryNode < Int > = new BinaryNode < Int > (7);
~~~
现在 ns.getContent() 会返回一个String类型的值,而ni.getContent() 会返回一个Int 类型的值。
你可以缩短类型声明,通过类型推断来减少代码:
~~~
var ns = new BinaryNode(“I’m a node”);
~~~
String类型参数可以被从构造器忽略,因为编译工具可以推断出正确的类型,从文本参数。变量不需要任何类型声明,因为完整类型可以通过构造器推断出来。
对象创建时的类型声明总是保留不变直到对象呗垃圾回收,在运行时不可改变。
给类参数名字 T 只是一个惯例。多于一个的类参数可以通过一个逗号分隔来指定,在括号中间。
类型参数也可以在函数层被指定;这个情况generic参数有一个目的只有在声明函数的上下文,而且和类的类型参数声明相同的方式,但是位于函数名后面。
~~~
public static function indexOf < T > (v : T, a : Array < T > )
{
for(i in 0...a.length)
if(v == a[i])
return i;
return -1;
}
~~~
这个函数有一个值类型T的参数,和一个相同类型数组,返回array中值得位置,如果没有找到返回-1 。这个函数被以传统方式使用:
~~~
var l = [1,2,4,8,16]; // l is of type Array < Int >
trace(indexOf(8, l));
~~~
这会输出3或者带有另一个类型的数组:
~~~
var ls = [“A”,”B”,”C”,”D”]; // ls is of type Array< String >
trace(indexOf(“C”, ls));
~~~
# 类型参数限制
* * * * *
通用的是有用的,但是太通用可能造成混淆。鉴于此,Haxe提供一个方式来限制类型参数只能使用一些类型。限制参数使用如下的语法:
~~~
class Name<T : Type, T : (Type, Type)>
~~~
圆括号的使用是强制消除歧义,当多于1个类参数使用的时候。多个约束通常是一个类和一个或者多个接口的结合;类型 T 必须满足所有列出的约束。类型约束不局限于类,还可以应用到接口中,enum,和 typedef 。
当使用类型约束,可以实现特定的对象容器,如下:
~~~
class Item
{
public function new() {}
}
class Movie extends Item { }
class Butterly extends Item { }
class Collection < T : Item >
{
public function new() {}
public function add(item : T)
{
// implementation goes here
}
}
~~~
在你的应用中你可以使用 Collection 类型来创建一个容器对于电影或者蝴蝶。
~~~
var movies = new Collection < Movie > (); // the constraint is on the class Movie
movies.add(new Movie()); // accepted value
movies.add(new Butterly()); // compiler does not permit this
~~~
约束也可以使用标准类型。一个约束Float类型可以限制数值的访问;在实例化中可以标记状态如果值必须是整数或实数。
~~~
class Point < T : Float >
{
public var x : T;
public var y : T;
public function new(x : T, y : T)
{
this.x = x;
this.y = y;
}
}
~~~
这个类可以像如下使用:
~~~
var pInt = new Point < Int > (10, 20);
// pInt.x = 0.1; // does not compile
var pFloat = new Point < Float > (0.1, 0.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
- 附加部分