问题
I'm attempting to treat an array of one type as an array of another (abstract) type. It works fine when I use the underlying type of the abstract. But when I attempt implicit conversion using another type (defined using @:from
keyword), I get a build failure.
It works if I use an explicit cast
, but I'm wondering - is there any way around this / something I'm missing?
In the example below, I get the build failure Array<Int> should be Array<StringAbstract>
class Test {
static function main() {
var test:String = "Hello World";
print(test); //this works
var testArr:Array<String> = ["Hello", "World"];
printArray(testArr); //this works (using underlying type)
var testInt:Int = 10;
print(testInt); //this works
var testIntArr:Array<Int> = [1, 2, 3];
printArray(cast testIntArr); //this works (explicit cast)
printArray(testIntArr); //build failure (using @:from)
}
static function print(s:StringAbstract) {
trace(s);
}
static function printArray(arr:Array<StringAbstract>) {
trace(arr);
}
}
abstract StringAbstract(String) from String to String {
inline function new(s:String) {
this = s;
}
@:from
static public function fromInt(i:Int) {
return new StringAbstract(Std.string(i));
}
}
Follow Up
Taking suggestions from Gama11 and Justinfront, I defined an abstract to convert arrays to arrays of my abstract type. But now I'm running into a different issue - as soon as I declare a @:from function, it breaks code that used to work.
Specifically, I used to be able to call my function with "mixed" types that were implicitly converted to the abstract (e.g. printArray([1, "2", 3]);
).
But as soon as I added a @:from
function to convert from a different type of array (Array<Int>
in this case), that functionality broke, with the error Arrays of mixed types are only allowed if the type is forced to Array<Dynamic>
.
Curious if anyone knows why this would be (example: https://try.haxe.org/#65D03).
class Test {
static function main() {
var testMixedArr:Array<StringAbstract> = [1, "2", 3];
printArray(testMixedArr); //this works
printArray([1, "2", 3]); //this doesn't work, unless I remove "fromIntArray" function
}
static function printArray(arr:StringAbstractArray) {trace(arr);}
}
abstract StringAbstractArray(Array<StringAbstract>) from Array<StringAbstract> to Array<StringAbstract> {
inline function new(s:Array<StringAbstract>) {
this = s;
}
@:from
static public function fromIntArray(intArr:Array<Int>) {
return new StringAbstractArray(Lambda.array( Lambda.map( intArr, function(i: Int):StringAbstract {
return i; } )));
}
}
回答1:
The only way around this is to define an explicit @:from
function that takes an Array<Int>
. The reason for this is explained in the Variance section of the Haxe Manual. It has a good example of how casting in this case can lead to unsafe code being executed at runtime (rather than being caught by the compiler).
回答2:
printArray( Lambda.array( Lambda.map( testIntArr, function(v: Int):StringAbstract {
return v; } )));
( No doubt with the new -> stuff it might be cleaner but foundation yet to update mac nightlies so can't play!)
回答3:
Follow up This works on try haxe, are you sure you need to even be doing this?
class Test {
static function main() {
var testMixedArr:Array<StringAbstract> = [1, "2", 3];
printArray(testMixedArr); //this works
printArray(new StringAbstractArray([1, "2", 3]));
}
static function printArray(arr:StringAbstractArray) {
trace(arr);
}
}
abstract StringAbstractArray(Array<StringAbstract>) from Array<StringAbstract> to Array<StringAbstract> {
inline public function new(s:Array<StringAbstract>) {
this = s;
}
@:from
static public function fromIntArray(intArr:Array<Int>) {
return new StringAbstractArray(Lambda.array( Lambda.map( intArr, function(i: Int):StringAbstract {
return i; } )));
}
}
abstract StringAbstract(String) from String to String {
inline function new(s:String) {
this = s;
}
@:from
static function fromInt(i:Int) {
return new StringAbstract(Std.string(i));
}
}
here:
http://try-haxe.mrcdk.com/#ED866
来源:https://stackoverflow.com/questions/43823767/haxe-abstracts-can-i-implicitly-cast-an-array-when-using-from