雖然變異也在其它地方意義重大,但是它特別經常和類型參數一起出現,并像一個驚喜。此外,非常容易觸發變異錯誤:
> While variance is also relevant in other places, it occurs particularly often with type parameters and comes as a surprise in this context. Additionally, it is very easy to trigger variance errors:
~~~
class Base {
public function new() { }
}
class Child extends Base { }
class Main {
public static function main () {
var children = [new Child()];
// Array<Child> should be Array<Base>
// Type parameters are invariant
// Child should be Base
var bases:Array<Base> = children;
}
}
~~~
顯然,一個 Array<Child> 不能被分配到一個 Array<Base>,即使 Child可以被分配到Base。原因可能比較意外:因為 array 可以被寫入,如通過它們的 push() 方法。忽略變異錯誤非常容易產生問題:
> Apparently,an `Array<Child>` cannot be assigned to an `Array<Base>`,even though `Child` can be assigned to `Base`. The reason for this might be somewhat unexpected: It is not allowed because arrays can be written to, e.g. via their `push()` method. It is easy to generate problems by ignoring variance errors:
~~~
class Base {
public function new() { }
}
class Child extends Base { }
class OtherChild extends Base { }
class Main {
public static function main () {
var children = [new Child()];
// subvert type checker
var bases:Array<Base> = cast children;
bases.push(new OtherChild());
for(child in children) {
trace(child);
}
}
}
~~~
這里我們使用 cast(第5.23節)破壞了類型檢查,因此允許了注釋行后的賦值。我們保存一個引用 bases 到原始的數組,類型為 Array<Base>。這使的推送另一個兼容Base的類型(OtherChild)到了數組。然而,我們原始的引用 children 仍然是 Array<Child>類型,當我們在迭代它的一個元素的時候遇到 OtherChild實例就會出現問題。
> Here we subvert the type checker by using a cast (5.23), thus allowing the assignment after the commented line. With that we hold a reference `bases` to the original array, typed as `Array<Base>`. This allows pushing another type compatible with `Base` (OtherChild) onto that array. However,our original reference `children` is still of type `Array<Child>` and things go bad when we encounter the `OtherChild` instance in one of its elements while iterating.
如果 Array 沒有 push() 方法,沒有其它修改的手段,賦值則變得安全,因為沒有矛盾的類型被添加到它。在Haxe中,我們可以使用結構子類型化(第3.5.2節)相應的限制類型來實現這個。
> If Array had no `push()` method and no other means of modi?cation,the assignment would be safe because no incompatible type could be added to it. In Haxe, we can achieve this by restricting the type accordingly using structural subtyping (3.5.2):
~~~
class Base {
public function new() { }
}
class Child extends Base { }
typedef MyArray<T> = {
public function pop():T;
}
class Main {
public static function main () {
var a = [new Child()];
var b:MyArray<Base> = a;
}
}
~~~
我們可以安全的分配 b 作為 MyArray<Base>類型,MyArray 只有一個 pop() 方法。沒有為 MyArray定義可以用來添加沖突類型的方法,因此被認為是協變的。
> We can safely assign with `b` being typed as `MyArray<Base>` and `MyArray` only having a `pop()` method. There is no method de?ned on `MyArray` which could be used to add incompatible types, it is thus said to be covariant.
**協變**
>[warning] 定義:協變
一種復合類型,如果它的組成類型可以被分配為缺少特定組件,如它們是只讀,不允許寫時,則被認為是協變的。
>[warning] De?nition: Covariance
A compound type is considered covariant if its component types can be assigned to less speci?c components, i.e. if they are only read, but never written.
>[warning] 定義:抗變性
一個復合類型,如果它的組件類型可以被分配得為缺少通用的組件,如它們只寫,但是不讀,則被認為是抗變。
>[warning] De?nition: Contravariance
A compound type is considered contravariant if its component types can be assigned to less generic components, i.e. if they are only written, but never read.
- 空白目錄
- 1.Haxe介紹
- 1.1.Haxe是什么
- 1.2.關于本文檔
- 1.2.1.作者及貢獻者
- 1.2.2.License
- 1.3Hello World
- 1.4.Haxe的歷史
- 2.類型
- 2.1.基本類型
- 2.1.1.數值類型
- 2.1.2.溢出
- 2.1.3.數值運算符
- 2.1.4.Bool類型
- 2.1.5.Void類型
- 2.2.為空性
- 2.2.1.可選參數和為空性
- 2.3.類實例
- 2.3.1.類的構造函數
- 2.3.2.繼承
- 2.3.3.接口
- 2.4.枚舉實例
- 2.4.1.Enum構造函數
- 2.4.2.使用枚舉
- 2.5.匿名結構
- 2.5.1.結構值的JSON形式
- 2.5.2. 結構類型的類記法
- 2.5.3.可選字段
- 2.5.4.性能影響
- 2.6.函數類型
- 2.6.1.可選參數
- 2.6.2.默認值
- 2.7.動態類型
- 2.7.1.Dynamic使用類型參數
- 2.7.2.實現Dynamic
- 2.8.抽象類型
- 2.8.1.隱式類型轉換
- 2.8.2.運算符重載
- 2.8.3.數組訪問
- 2.8.4.選擇函數
- 2.8.5.枚舉抽象類型
- 2.8.6.轉發抽象類型字段
- 2.8.7.核心類型抽象
- 2.9.單形
- 3.類型系統
- 3.1.Typedef
- 3.1.1.擴展
- 3.2.類型參數
- 3.2.1.約束
- 3.3.泛型
- 3.3.1.泛型類型參數解釋
- 3.4.變異
- 3.5.統一
- 3.5.1.類/接口 之間
- 3.5.2.結構子類型化
- 3.5.3.單形
- 3.5.4.函數返回
- 3.5.5.通用基本類型
- 3.6.類型推斷
- 3.6.1.由上而下推斷
- 3.6.2.局限
- 3.7.模塊和路徑
- 3.7.1.模塊子類型
- 3.7.2.Import
- 3.7.3.解析順序
- 4.類字段
- 4.1.變量
- 4.2.屬性
- 4.2.1.常見訪問標識符組合
- 4.2.2.對類型系統的影響
- 4.2.3.getter和setter的規則
- 4.3.方法
- 4.3.1.重寫方法
- 4.3.2.變異和訪問修飾符的影響
- 4.4.訪問修飾符
- 4.4.1.可見性
- 4.4.2.Inline
- 4.4.3.Dynamic
- 4.4.4.Override
- 4.4.5.Static
- 5.表達式
- 5.1.塊
- 5.2.常量
- 5.3.二元操作符
- 5.4.一元操作符
- 5.5.數組聲明
- 5.6.對象聲明
- 5.7.字段訪問
- 5.8.數組訪問
- 5.9.函數調用
- 5.10.var
- 5.11.局部函數
- 5.12.new
- 5.13.for
- 5.14.while
- 5.15.do-while
- 5.16.if
- 5.17.switch
- 5.18.try/catch
- 5.19.return
- 5.20.break
- 5.21.continue
- 5.22.throw
- 5.23.類型轉換
- 5.23.1.不安全轉換
- 5.23.2.安全轉換
- 5.24.類型檢查
- 6.語言特性
- 6.1.條件編譯
- 6.2.Externs
- 6.3.靜態擴展
- 6.3.1.標準庫中的靜態擴展
- 6.4.模式匹配
- 6.4.1.介紹
- 6.4.2.枚舉匹配
- 6.4.3.變量捕獲
- 6.4.4.結構匹配
- 6.4.5.數組匹配
- 6.4.6.Or 模式
- 6.4.7.守護
- 6.4.8.多個值的匹配
- 6.4.9.提取器
- 6.4.10.窮盡性檢查
- 6.4.11.無效的模式檢查
- 6.5.字符串插值
- 6.6.數組推導
- 6.7.迭代器
- 6.8.函數綁定
- 6.9.元數據
- 6.10.訪問控制
- 6.11.內聯構造函數
- 7.編譯器用法
- 7.1.編譯器標記
- 8.編譯器功能
- 8.1.內建編譯器元數據
- 8.2.無用代碼消除
- 8.3.編譯器服務
- 8.3.1.概述
- 8.3.2.字段訪問完成
- 8.3.3.調用參數完成
- 8.3.4.類型路徑完成
- 8.3.5.使用完成
- 8.3.6.位置完成
- 8.3.7.頂級完成
- 8.3.8.完成服務
- 8.4.資源
- 8.4.1.嵌入資源
- 8.4.2.檢索文本資源
- 8.4.3.檢索二進制資源
- 8.4.4.實現細節
- 8.5.運行時類型信息
- 8.5.1.RTTI 結構
- 8.6.靜態分析儀
- 9.宏
- 9.1.宏上下文
- 9.2.參數
- 9.2.1.ExprOf
- 9.2.2.常數表達式
- 9.2.3.其它的參數
- 9.3.具體化
- 9.3.1.表達式具體化
- 9.3.2.類型具體化
- 9.3.3.類具體化
- 9.4.工具
- 9.5.類型構建
- 9.5.1.枚舉構建
- 9.5.2.@:autoBuild
- 9.5.3.@:genericBuild
- 9.6.限制
- 9.6.1.Macro-in-Macro
- 9.6.2.靜態擴展
- 9.6.3.構建順序
- 9.6.4.類型參數
- 9.7.初始化宏
- 10.標準庫
- 10.1.字符串
- 10.2.數據結構
- 10.2.1.數組
- 10.2.2.向量
- 10.2.3.列表
- 10.2.4.GenericStack
- 10.2.5.Map
- 10.2.6.Option
- 10.3.正則表達式
- 10.3.1.匹配
- 10.3.2.分組
- 10.3.3.替換
- 10.3.4.分割
- 10.3.5.Map
- 10.3.6.實現細節
- 10.4.Math
- 10.4.1.特殊數值
- 10.4.2.數學錯誤
- 10.4.3.整數數學
- 10.4.4.擴展
- 10.5.Lambda
- 10.6.模板
- 10.7.反射
- 10.8.序列化
- 10.8.1.格式化序列化
- 10.9.Xml
- 10.9.1.開始使用Xml
- 10.9.2.解析Xml
- 10.9.3.編碼Xml
- 10.10.Json
- 10.10.1.解析JSON
- 10.10.2.編碼JSON
- 10.10.3.實現細節
- 10.11.Input/Output
- 10.12.Sys/sys
- 10.13.遠程處理
- 10.13.1.遠程連接
- 10.13.2.實現細節
- 10.14.單元測試
- 11.Haxelib
- 11.1.Haxe編譯器使用庫
- 11.2.haxelib.json
- 11.2.1.版本控制
- 11.2.2.依賴關系
- 11.3.extraParams.hxml
- 11.4.使用Haxelib
- 12.目標平臺細節
- 12.1.JavaScript
- 12.1.1.開始使用Haxe/JavaScript
- 12.1.2.使用外部JavaScript庫
- 12.1.3.注入原生JavaScript
- 12.1.4.JavaScript untyped函數
- 12.1.5.調試JavaScript
- 12.1.6.JavaScript目標元數據
- 12.1.7.為JavaScript暴露Haxe類
- 12.1.8.使用 require函數加載外部類
- 12.2.Flash
- 12.2.1.開始使用Haxe/Flash
- 12.2.2.嵌入資源
- 12.2.3.使用外部Flash庫
- 12.2.4.Flash目標元數據
- 12.3.Neko
- 12.4.PHP
- 12.4.1.開始使用Haxe/PHP
- 12.4.2.PHP untyped函數
- 12.5.C++
- 12.5.1.Using C++定義
- 12.5.2.Using C++ 指針
- 12.6.Java
- 12.7.C#
- 12.8.Python