Haxe abstracts - Can I implicitly cast an array when using @:from?

旧街凉风 提交于 2019-12-14 03:54:30

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!