Typedef 是一个定义用于匿名类型类型检查的类型的构造。Typedef 声明必须使用如下语法:
~~~
typedef Name = typedeclaration
~~~
Name必须遵守和类名相同的命名规则, typedeclaration 是类型定义的签名。
最常见的用法关于 typedef 是给一个匿名对象以形式的表现。
~~~
typedef Color = { r: Int, g: Int, b: Int}
~~~
这样使用:
~~~
var white : Color = { r: 255, g: 255, b: 255 };
~~~
typedef hi可以用来定义其他类型,如函数或者已有定义的快捷方式。
~~~
typedef GenericFunction < T > = Void - > T
typedef IntArray = Array < Int >
typedef P = Person
typedef TS = ThreeState
enum ThreeState
{
Checked;
Unchecked;
Indeterminated;
}
class Person
{
public var name : String;
public function new() { }
}
~~~
当声明一个匿名对象的类型,有两种语法的可能:
~~~
typedef A = {
var x : Float;
var y : Float;
}
typedef B = {
x : Float,
y : Float
}
~~~
这种情况下,声明是等价的,但是你可以发现不同于一个包含至少有一个函数定义的 typedef :
~~~
typedef A = {
function say(text : String) : String;
}
typedef B = {
say : String - > String
}
~~~
在这种情况,两个几乎一样,唯一区别是函数参数在第一个声明被命名,而第二个则匿名。另外的不同是第一个格式里可以添加 private/public 访问修饰符(默认总是 public )。
typedef 还可以有类型参数,和类跟接口类似。
~~~
typedef Leaf < T > = {
parent : Node < T > ,
data : T
}
~~~
typedef 语法是一个重要的Haxe语言特性。 typedef 在很多方面是一个灵活的接口替代选择。typedef验证只在编译时发生并且知识结构上检查;编译器检查传递的对象有需要的字段但是不假设对象的类型定义。这创造了有趣的可能性,下面的例子,handle() 函数接受一个HashNme类型的参数。HasName是一个 typedef,定义它的类型的值必须有一个String类型的name字段。好处是不只是匿名对象可以满足这个结构要求,而类的实例同样可以。
~~~
class Person
{
public var name : String;
public function new(n : String)
{
name = n;
}
}
class Item
{
public var name : String;
public var price : Float;
public function new(n : String, p : Float)
{
name = n;
price = p;
}
}
typedef HasName = {
name : String
}
class Main
{
public static function handle(o : HasName)
{
trace(o.name);
}
public static function main()
{
var person = new Person(“John”);
var item = new Item(“Laptop PC”, 999.9);
var user = { name : “Jane” };
handle(person);
handle(item);
handle(user);
}
}
~~~
你可以简化声明移除 typedef 定义并且替换处理声明通过如下行:
~~~
public static function handle(o : { name : String})
~~~
typedef并不是嵌入到生成的输出中,而是只用于类型在编译时的检查。他们执行了一种基于惯例的编程,开发人员需要构造带有某些特征的结构但并不需要绑定到类似接口或者基类的形式定义。可以定义一个约定对于一个项目,而不用提供任何代码让同僚实现一个完整的应用。这可以在Web开发环境中带来很大的好处,通常有许多库可以帮助我们工作。
不仅使用在对象,而且任何类型定义都可以使用。举个有趣的例子,有一个函数接收另一个函数作为参数;参数可能是一个内联函数,一个对象方法,或者一个类静态函数。这里有一个例子:
~~~
class StringDecoration
{
var prefix : String;
public function new(prefix : String)
{
this.prefix = prefix;
}
public function decorate(s : String)
{
return prefix + s;
}
}
class Main
{
public static function print(s : String, decorate : String -> String)
{
var o = decorate(s);
trace(o);
}
public static function quote(s : String)
{
return ‘”’ + s + ‘”’;
}
public static function main()
{
var decorator = new StringDecoration(“- > “);
var s = “John”;
print(s, quote); // traces “John”
print(s, decorator.decorate); // traces - > John
print(s, function(s){ return “-- “ + s + “ --”; }); // traces -- John -
}
}
~~~
print()的第二个参数是一个typedef对一个接收一个字符串作为参数并返回一个String的函数。在 main() 方法,pirnt()函数用来传递静态函数 quote(),然后类StringDecoration的实例函数 decorate(),最后一个内联函数定义。
# 迭代器和可迭代性
* * * * *
在Haxe标准库中,两个非常常用的typedef是:Iterator<T> 和 Iterable<T>。
它们的定义如下:
~~~
typedef Iterator < T > = {
function hasNext() : Bool;
function next() : T;
}
typedef Iterable < T > = {
function iterator() : Iterator < T > ;
}
~~~
因为在第三章已经了解过,这些结构被定义来处理对象集合,他们很容易的实现在类定义中。这个例子里,一个随机的迭代器被定义。迭代器会返回一个n个随机字符的序列。
~~~
class RandomSequence
{
private var letters : Int;
private var counter : Null < Int > ;
public function new(letters : Int)
{
this.letters = letters;
}
public function hasNext() : Bool
{
if(counter == null)
{
// the iterator has to be initialized
counter = 0;
}
if(counter < letters)
{
return true;
} else {
// before returning false, the counter variable must
// be reset in case the instance has to be used again
counter = null;
return false;
}
}
public function next() : String
{
counter++;
return Std.chr(Std.int(Math.random() * 26)+ 65);
}
}
~~~
代码不显式声明,它是实现Iterator typedef 。这个隐式发生因为类定义正确的方法。这个类这样使用:
~~~
class Main
{
static function main()
{
var sequence = new RandomSequence(10);
for(letter in sequence)
{
trace(letter);
}
}
}
~~~
这个例子会输出十次随机字母。
在实践中Haxe在背后做的死改变 for(序列中的字母)声明:
~~~
while(sequence.hasNext())
{
var letter = sequence.next();
// ...
}
~~~
这自动发生每次一个用在for语句中的对象符合 Iterator<T> typedef 。相同的处理是被保留对符合Iterable<T>的对象。这可以用在当对象可以返回一个结合但是有一个间接的中介。
Array<T>是 Iterable<T>,可以用来演示它的用法。下面的两个声明实际上是相同的;编译器在内部改变第二个使其表现的像第一个。
~~~
for(i in [1,2,4,8].iterator())
{
trace(i);
}
for(i in [1,2,4,8])
{
trace(i);
}
~~~
- 本书目录
- 第一章: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
- 附加部分