Skip to content

Latest commit

 

History

History
187 lines (144 loc) · 8.12 KB

3.3.泛型.md

File metadata and controls

187 lines (144 loc) · 8.12 KB

3.3.泛型

通常,Haxe编译器只生成一个单独的类或者函数,即使它有类型参数。生成的代码之后可能必须执行一些类型检查可能会影响一些性能。这发生在一个自然抽象概念中,目标语言的代码生成器必须假设一个类型参数可以是任何类型。

Usually, the Haxe Compiler generates only a single class or function even if it has type parameters. This results in a natural abstraction where the code generator for the target language has to assume that a type parameter could be of any type. The generated code then might have to perform some type checks which can be detrimental to performance.

*一个类或者函数可以通过使用 :generic 元数据(第6.9节)归类为泛型。这导致编译器每个类型参数和破损的名字的混合,发射一个不同的类/函数。*一个这样的规范可以使得静态目标语言(第2.2节)的部分 性能关键型(performance-critical) 的代码得到性能提升,但代价是其生成的体量变大:

A class or function can be made generic by attributing it with the :generic metadata (6.9). This causes the compiler to emit a distinct class/function per type parameter combination with mangled names. A specification like this can yield a boost in performance-critical code portions on static targets (2.2) at the cost of a larger output size:

@:generic
class MyValue<T> {
    public var value:T; 
    public function new(value:T) { 
        this.value = value; 
    } 
}

class Main { 
    static public function main() { 
        var a = new MyValue<String>("Hello"); 
        var b = new MyValue<Int>(42); 
    }
} 

似乎不常见这里的显式类型 MyValue,因为我们通常让类型推断(第3.6节)处理它。尽管如此,它确实需要在这种情况下被需要。编译器必须了解泛型类的准确类型一经构建。JavaScript输出显示结果:

It seems unusual to see the explicit type MyValue here as we usually let type inference (3.6) deal with this. Nonetheless, it is indeed required in this case. The compiler has to know the exact type of a generic class upon construction. The JavaScript output shows the result:

(function () { "use strict";
    var Test = function() { }; 
    Test.main = function() { 
        var a = new MyValue_String("Hello"); 
        var b = new MyValue_Int(5);
    }; 
    var MyValue_Int = function(value) { 
        this.value = value; 
    }; 
    var MyValue_String = function(value) { 
        this.value = value; 
    }; 
    Test.main(); 
})();

我们可以确定 MyValue和MyVlue 已经变成 MyValue_String 和MyValue_Int 。这类似于泛型函数:

We can identify that MyValue and MyValue have become MyValue_String and MyValue_Int respectively. This is similar for generic functions:

class Main { 
    static public function main() { 
        method("foo");
        method(1); 
    }
    
    @:generic static function method<T>(t:T) { } 
} 

再一次,JavaScript输出使其非常明显:

Again, the JavaScript output makes it obvious:

(function () { "use strict"; 
    var Main = function() { }
    Main.method_Int = function(t) { 
    }
    Main.method_String = function(t) { 
    }
    Main.main = function() {
        Main.method_String("foo"); 
        Main.method_Int(1); 
    }
    Main.main();
})();

3.3.1.泛型类型参数解释

定义:泛型类型参数 如果它的包含类或者方法是泛型,则一个类型参数被认为是泛型。 [warning] Definition: Generic Type Parameter A type parameter is said to be generic if its containing class or method is generic.

不可能构建一般的类型参数,例如 new T() 会有编译器错误。理由是Haxe只生成一个单独的函数,而且构造毫无意义。当类型参数为泛型的时候则不同:因为我们知道编译器会生成一个不同的函数对于每个类型参数组合,可以使用真实的类型替换 T new T()。

It is not possible to construct normal type parameters, e.g. new T() is a compiler error. The reason for this is that Haxe generates only a single function and the construct makes no sense in that case. This is different when the type parameter is generic: Since we know that the compiler will generate a distinct function for each type parameter combination,it is possible to replace the T new T() with the real type.

typedef Constructible = {
    public function new(s:String):Void; 
}
    
class Main {
    static public function main() { 
        var s:String = make();
        var t:haxe.Template = make(); 
    } 
    
    @:generic 
    static function make<T:Constructible>():T { 
        return new T("foo");
    }
} 

应该注意,这里使用从下到下的推断(第3.6.1节)来确定T的实际类型。这种类型的类型参数构建有两个需求才能工作:构建的类型参数必须是

It should be noted that top-down inference (3.6.1) is used here to determine the actual type of T. There are two requirements for this kind of type parameter construction to work: The constructed type parameter must be

  • 是泛型,而且
  • 显式约束(第3.2.1节)为有一个构造参数(第2.3.1节)
  • generic and
  • be explicitly constrained (3.2.1) to having a constructor (2.3.1).

这里,1,通过使用有 @generic 元数据,2. 通过 T 被约束为可构造的。这个约束适用于String 和haxe.Template 因为它们都有一个构造函数,接受一个单一的Sting参数。果然,相关的JavaScript输出看起来和预期的一样:

Here, 1. is given by make having the @:generic metadata, and 2. by T being constrained to Constructible. The constraint holds for both String and haxe.Template as both have a constructor accepting a singular String argument. Sure enough, the relevant JavaScript output looks as expected:

var Main = function() { } 
Main.__name__ = true; 
Main.make_haxe_Template = function() {
    return new haxe.Template("foo"); 
}
Main.make_String = function() { 
    return new String("foo"); 
}
Main.main = function() {
    var s = Main.make_String(); 11 var t = Main.make_haxe_Template(); 
}

A type parameter is said to be generic if its containing class or method is generic.

It is not possible to construct normal type parameters; for example, new T() would register as a compiler error. The reason for this is that Haxe generates only a single function and the construct would make no sense in that case. This is different when the type parameter is generic: since we know that the compiler will generate a distinct function for each type parameter combination, it is possible to replace the T new T() with the real type.

import haxe.Constraints;

class Main {
  static public function main() {
    var s:String = make();
    var t:haxe.Template = make();
  }

  @:generic
  static function make<T:Constructible<String->Void>>():T {
    return new T("foo");
  }
}

It should be noted that top-down inference is used here to determine the actual type of T. For this kind of type parameter construction to work, the constructed type parameter must meet two requirements:

  1. It must be generic.
  2. It must be explicitly constrained to have a constructor.

Here, the first requirement is met by make having the @:generic metadata, and the second by T being constrained to Constructible. The constraint holds for both String and haxe.Template as both have a constructor accepting a singular String argument. Sure enough, the relevant JavaScript output looks as expected:

var Main = function() { }
Main.__name__ = true;
Main.make_haxe_Template = function() {
    return new haxe.Template("foo");
}
Main.make_String = function() {
    return new String("foo");
}
Main.main = function() {
    var s = Main.make_String();
    var t = Main.make_haxe_Template();
}