我有这部分代码:
class Main {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
if (f == null) {
f = (a, b) -> a - b;
}
return f(a, b);
}
static function main() {
trace(difference(42, 37));
trace(difference(42, 37, (a, b) -> a - b));
}
}
Run Code Online (Sandbox Code Playgroud)
其中,当我使用 编译时haxe --main Main,会因以下错误而失败:
class Main {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
if (f == null) {
f = (a, b) -> a - b;
}
return f(a, b);
}
static function main() {
trace(difference(42, 37));
trace(difference(42, 37, (a, b) -> a - b));
}
}
Run Code Online (Sandbox Code Playgroud)
如果我更改Main.difference为不内联,则不会出现此错误并且一切都可以正常编译。
为什么会出现这个错误?
编辑:我发现我也可以先将参数分配给变量,然后将变量传递给Main.difference,如下所示:
static function main() {
var f = (a, b) -> a - b;
trace(difference(42, 37, f));
}
Run Code Online (Sandbox Code Playgroud)
Main.difference内联可以很好地工作。但是,首先将函数分配给变量如何改变事情?
这与编译器如何解包内联函数有关。让我们采用更简单的代码变体:
class HelloWorld {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
return f(a, b);
}
static function main() {
trace(difference(42, 37, (a, b) -> a - b));
}
}
Run Code Online (Sandbox Code Playgroud)
禁用优化时,这将产生以下 JavaScript:
class HelloWorld {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
return f(a, b);
}
static function main() {
trace(difference(42, 37, (a, b) -> a - b));
}
}
Run Code Online (Sandbox Code Playgroud)
因此,difference已经使用 JavaScript 闭包将of 的主体合并到 main 中。我对在您的确切情况下发生的事情的最佳猜测是这样的:
HelloWorld.main = function() {
console.log("HelloWorld.hx:14:",(function(a,b) {
return a - b;
})(42,37));
};
Run Code Online (Sandbox Code Playgroud)
这会更改 的值v,该值存在于 之外difference,该值已自动放置在那里作为匿名 lambda 的绑定。这是编译器试图避免的。在您的情况下,这不会是世界末日,但总的来说,这很糟糕,会导致许多程序出现问题。
有一种方法可以在没有这个的情况下手动完美地内联此代码,但我认为围绕匿名 lambda 的当前处理方式存在一些奇怪之处。未来情况可能会有所改善。
当您f在 main 中显式定义时,编译器足够智能,可以将嵌套重命名f为f1,这就是问题不会发生的原因:
HelloWorld.main = function() {
var v = function(a,b) {
return a - b;
}
console.log("HelloWorld.hx:14:", (function(a,b) {
if (v == null) {
v = function(a, b) {
return a - b;
}
}
return v(a, b);
})(42, 37));
};
Run Code Online (Sandbox Code Playgroud)
但是,如果inline此功能的一部分对您很重要,这也将起作用:
class HelloWorld {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
var h = f;
if (h == null) {
h = (a, b) -> a - b;
}
return h(a, b);
}
static function main() {
trace(difference(42, 37, (a, b) -> a - b));
}
}
Run Code Online (Sandbox Code Playgroud)