Предположим, у вас есть функция extern, которая принимает аргумент Null<Int>
.
Этот аргумент требуется в целевом API, но вы хотите, чтобы по умолчанию он был равен 0 при вызове из Haxe. То есть
class Test {
static function main() {
Ext.func();
Ext.func(1);
Ext.func(null);
}
}
extern class Ext { ... definition for func }
должно выдать
Ext.func(0);
Ext.func(1);
Ext.func(null);
соответственно.
Это странно проблематично, давайте пока рассмотрим мои соображения:
Очевидный подход
class Test {
static function main() {
Ext.func();
Ext.func(0);
Ext.func(null);
}
}
extern class Ext {
static function func(v:Null<Int> = 0):Void;
}
Производит
Ext.func(); // (note the omitted parameter)
Ext.func(0);
Ext.func(null);
и, следовательно, ваш сгенерированный код не компилируется.
Встроенная оболочка
class Test {
static function main() {
Ext.func();
Ext.func(1);
Ext.func(null);
}
}
extern class Ext {
static inline function func(v:Null<Int> = 0):Void {
realFunc(v);
}
@:native("func") private static function realFunc(v:Null<Int>):Void;
}
Производит
Ext.func(0);
Ext.func(1);
Ext.func(0); // (note the null turning into 0)
и, следовательно, ваш код не работает должным образом.
Макросы
Как гласит старая поговорка , любое упущение в Haxe можетбыть исправлено с помощью достаточно сложного макроса. Это подтверждается еще раз, но по какой цене?
Test.hx:
class Test {
static function main() {
Ext.func();
Ext.func(1);
Ext.func(null);
}
}
RealExt.hx:
@:native("Ext") extern class RealExt {
static function func(v:Null<Int>):Void;
}
Ext.hx:
import haxe.macro.Expr;
class Ext {
public static macro function func(args:Array<Expr>):Expr {
if (args.length > 1) throw "Too many arguments!";
var v = args[0];
if (v == null) v = macro 0;
return macro RealExt.func($v);
}
}
Таким образом, мы не можем поместить макрос во внешний класс, поэтому нужен прокси-класс (если вы хотели это в служебном классе, я думаю, вы теперь получили избыточность ... если вы не хотите написатьмакрос, который перебирает поля класса и строит прокси-класс?), и вы не можете просто иметь необязательный аргумент? expr (или он превратится в EConst (CIdent (null)))), так что это небольшое чудовище. Но это работает, да
Ext.func(0);
Ext.func(1);
Ext.func(null);
Признавая свое поражение
Может быть, все не так просто, как нам хотелось бы.
class Test {
static function main() {
Ext.func();
Ext.funcExt(1);
Ext.funcExt(null);
}
}
extern class Ext {
static inline function func():Void {
funcExt(0);
}
@:native("func") static function funcExt(v:Null<Int>):Void;
}
Очевидно, это работает,
Ext.func(0);
Ext.func(1);
Ext.func(null);
но выглядит не очень чисто.
Не признаю вашего поражения
Не знаю, лучше это или хуже
class Test {
static function main() {
Ext.func();
Ext.func(1);
Ext.funcWithNull();
}
}
extern class Ext {
static inline function func(v:Null<Int> = 0):Void {
funcExt(v);
}
static inline function funcWithNull():Void {
funcExt(null);
}
@:native("func") private static function funcExt(v:Null<Int>):Void;
}
Очевидно, что это работает, только если вы знаете, что будете вызывать его с помощью null
, и также не работает, если существует более одного такого аргумента.
Использование магического значения для указания того, что выхотел ноль
Это звучит как просьба о неприятностях, может, давайте не будем
Возможно, есть лучший способ сделать это?