Skip to content

Latest commit

 

History

History
106 lines (82 loc) · 4.84 KB

2.7.动态类型.md

File metadata and controls

106 lines (82 loc) · 4.84 KB

2.7.动态类型

虽然 Haxe 有一个静态的类型系统,但这个类型系统实际上可以通过使用 Dynamic 类型关闭。一个 动态值可以被赋值给任何类型;而任何值都可以被分配到动态类型。这有一些缺点:

  • 编译器将不会再在接受指定类型的赋值、函数调用和其它构造中进行类型检查。
  • 某些优化,特别是编译为静态目标语言时,将不能再被使用。
  • 一些常见的错误,例如字段访问中的一个拼写错误,将不能在编译时被发现,可能会引发运行时的错误。
  • 如果字段是通过 Dynamic 类型使用,无用代码消除(第8.2节) 不能检测使用到的字段

使用 Dynamic 类型可能引发运行时错误的例子非常容易出现。思考下面的两行代码到静态目标语言的编译:

var d:Dynamic = 1; 
d.foo;

尝试在 Flash 播放器运行编译后的程序,会产生一个错误 ,属性 foo 在 数值类型中没有找到,而且没有默认值。不使用 Dynamic,这会在编译时被侦测到。

花絮:Haxe 3之前的 Dynamic 类型推断 Haxe 3 编译器从不推断一个类型为 Dynamic 类型,所以用户必须明确它。之前的 Haxe 版本曾经推断 数组为一个混合类型,如 [1, true, "foo"]Array。我们发现这个行为会引发太多的类型问题,因此在 Haxe 3 中移除了它。

应该尽量少的使用 Dynamic 类型,因为很多情况下都有更好的选择,但是有时候实际会用到它。Haxe 反射(第10.7节) API中部分使用了 Dynamic 类型,而且有时候它是在处理编译时未知的自定义数据结构最好选择。当被用一个 单形(第2.9节)统一(第3.5节) 的时候,Dynamic 类型以一种特殊的方式运行。单形没有绑定到 Dynamic,这可以在如下例子中带来令人惊喜的结果:

class Main { 
    static function main() { 
        var jsonData = ’[1, 2, 3]’; 
        var json = haxe.Json.parse(jsonData); 
        $type(json); // Unknown<0> 
        for (i in 0...json.length) { 
            // Array access is not allowed on 
            // {+ length : Int } 
            trace(json[0]); 
        }
    }
} 

尽管 Json.parse 的返回类型是 Dynamic 类型,局部变量 json 的类型并没有绑定到动态类型,仍然保持了一个单形。然后它在 json.length 字段访问上被推断为一个 匿名结构(第2.5节),使后面的 json[0] 数组访问失败。为了避免这个问题,变量 json 可以通过使用 var json:Dynamic 显式的声明为 Dynamic 类型。

花絮:标准库中的 Dynamic 类型 Dynamic 类型在 Haxe 3 之前非常频繁的使用在标准库中。随着 Haxe 类型系统的持续改进,Dynamic 类型的出现在通往 Haxe 3的版本被减少。

2.7.1.Dynamic使用类型参数

Dynamic 是一个特殊的类型,因为它允许使用和不使用一个 类型参数(第3.2节) 来进行显式的声明。如果这样一个类型参数被提供,Dynamic(第2.7节) 中描述的 语义被限制为所有的字段兼容该参数类型:

var att : Dynamic<String> = xml.attributes;
// 有效, 值为一个 String 类型 
att.name = "Nicolas"; 
// dito (这个文档太旧了) 
att.age = "26"; 
// error,值不是 String 类型
att.income = 0;

2.7.2.实现Dynamic

类可以 实现(第2.3.3节) Dynamic 类型,和提供任意字段访问的 Dynamic 。前一种情况,字段可以有任何类型,而后一种,它们被限制兼容参数类型:

 class ImplementsDynamic 
    implements Dynamic<String> { 
        public var present:Int; 
        public function new() {} 
}
class Main {
    static public function main() {
        var c = new ImplementsDynamic(); 
        // 有效的,present 是一个存在的字段 
        c.present = 1; 
        // 有效,分配的值是一个 String 
        c.stringField = "foo"; 
        // 错误,Int应该是 String 
        //c.intField = 1;
    }
} 

实现 Dynamic 不符合实现其它接口的需求。预期的字段仍然必须被明确实现。实现 Dynamic 的类(带或者不带类型参数)也可以利用一个特别的方法名字叫做 resolve 。如果一个 读访问(第4.2节) 被做出,而且被讨论的字段不存在,resolve 方法被调用,并以这个字段的名字作为参数:

class Resolve implements Dynamic<String> { 
    public var present:Int;
    public function new() {} 
    function resolve(field:String) { 
        return "Tried to resolve " +field; 
    }
}

class Main { 
    static public function main() { 
        var c = new Resolve();
        c.present = 2; 
        trace(c.present); 
        trace(c.resolveMe);
    }
}