一些類或接口是特定操作其他類的實例。這些操作可以被在不分享任何通用父類或接口類的實例執行。考慮如下例子:
~~~
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
- 附加部分