代码之家  ›  专栏  ›  技术社区  ›  0x.dummyVar

Haxe:使用抽象来定义类型组

  •  2
  • 0x.dummyVar  · 技术社区  · 6 年前

    到目前为止,我已经通读了: https://haxe.org/manual/types-abstract.html , https://haxe.org/blog/abstracting-primitives/ , http://old.haxe.org/manual/abstracts https://code.haxe.org/category/other/passing-different-types-to-a-function-parameter.html . 如果有人有其他资料可以告诉我,我会很感激的。

    我基本上是在尝试创建一个接受类型为的变量的函数 String , Int Float ,或 Bool ,并追踪它。不过,当我尝试编译时 haxe -main Main -cpp Export abstracts/Comparison.hx:99: characters 42-43 : Type not found : A . 我正试图找出为什么会发生这种情况,以及如何解决它。

    我觉得我附加了太多代码,但这是我目前为止所写的:

    主.hx

    import abstracts.*;
    
    class Main
    {
        public static function main()
        {
            var toPrint:Array<String> = ["String1", "String2", "String3"];
            printArray(toPrint);
        }
    
        public static function printArray(toPrint:PrintableArray)
        {
            for (element in toPrint)
            {
                trace(element);
            }
        }
    }
    

    abstracs公司/比较.hx

    package abstracts;
    
    enum Either<A, B>
    {
        Left(v:A);
        Right(v:B);
    }
    
    abstract Of2<A, B>(Either<A, B>) from Either<A, B> to Either<A, B>
    {
        @from inline static function fromA<A, B>(a:A):Of2<A, B>
        {
            return Left(a);
        }
        @from inline static function fromB<A, B>(b:B):Of2<A, B>
        {
            return Right(b);
        }
    
        @to inline static function toA():Null<A>
        {
            return switch (this)
            {
                case Left(a): a;
                default: null;
            }
        }
        @to inline static function toB():Null<B>
        {
            return switch (this)
            {
                case Right(b): b;
                default: null;
            }
        }
    }
    
    abstract Of3<A, B, C>(Either<Either<A, B>, C>) from Either<Either<A, B>, C> to Either<Either<A, B>, C>
    {
        @from inline static function fromA<A, B, C>(a:A):Of3<A, B, C>
        {
            return Left(Left(a));
        }
        @from inline static function fromB<A, B, C>(b:B):Of3<A, B, C>
        {
            return Left(Right(b));
        }
        @from inline static function fromC<A, B, C>(c:C):Of3<A, B, C>
        {
            return Right(c);
        }
    
        @to inline static function toA():Null<A>
        {
            return switch (this)
            {
                case Left(Left(a)): a;
                default: null;
            }
        }
        @to inline static function toB():Null<B>
        {
            return switch (this)
            {
                case Left(Right(b)): b;
                default: null;
            }
        }
        @to inline static function toC():Null<C>
        {
            return switch (this)
            {
                case Right(c): c;
                default: null;
            }
        }
    }
    
    abstract Of4<A, B, C, D>(Either<Either<A, B>, Either<C, D>>) from Either<Either<A, B>, Either<C, D>> to Either<Either<A, B>, Either<C, D>>
    {
        @from inline static function fromA<A, B, C, D>(a:A):Of4<A, B, C, D>
        {
            return Left(Left(a));
        }
        @from inline static function fromB<A, B, C, D>(b:B):Of4<A, B, C, D>
        {
            return Left(Right(b));
        }
        @from inline static function fromC<A, B, C, D>(c:C):Of4<A, B, C, D>
        {
            return Right(Left(c));
        }
        @from inline static function fromD<A, B, C, D>(d:D):Of4<A, B, C, D>
        {
            return Right(Right(d));
        }
    
        @to inline static function toA():Null<A>
        {
            return switch (this)
            {
                case Left(Left(a)): a;
                default: null;
            }
        }
        @to inline static function toB():Null<B>
        {
            return switch (this)
            {
                case Left(Right(b)): b;
                default: null;
            }
        }
        @to inline static function toC():Null<C>
        {
            return switch (this)
            {
                case Right(Left(c)): c;
                default: null;
            }
        }
        @to inline static function toD():Null<D>
        {
            return switch (this)
            {
                case Right(Right(d)): d;
                default: null;
            }
        }
    }
    

    摘要/可打印.hx

    package abstracts;
    
    abstract Printable(Comparison.Of4<String, Int, Float, Bool>) {}
    

    摘要/PrintableArray.hx

    package abstracts;
    
    abstract PrintableArray(Array<Printable.Printable>) {}
    

    3 回复  |  直到 6 年前
        1
  •  0
  •   Gama11 zzapper    6 年前

    这个 Type not found : A 尝试访问类型的类型参数时导致错误 在静态函数中。静态函数只能访问在函数本身上声明的类型参数。 @:to static ,所以您可以简单地删除关键字。

    但还有更多的问题:

    • @from @to 而不是 @:from @:至 ,这意味着你的转换方法不会有任何效果。
    • 即使换成 @:来自 fromA / fromB / fromC / fromD String / Int /可作为选择依据的etc类型。你可能需要混凝土 fromString / fromInt /etc功能。
    • 抽象的隐式转换是 不可传递 ( see example at the bottom here ). 这意味着你的 Printable 抽象不允许隐式转换。它可以是一个简单的 typedef

      typedef Printable = Comparison.Of4<String, Int, Bool, Float>;
      
    • 类似地,您不能在 PrintableArray iterator() method forwarded ,例如 @:forward(iterator) . 这可能会导致诸如 here from Array<Printable> -简而言之,a 类型定义

    • 即使上述所有问题都已解决,您的 trace() 不会有期望的输出。含蓄的 @:至 这里不应用强制转换,因为它们是编译时特性,并且 跟踪() 接受 Dynamic . 你最终会得到这样的结果:

      source/Main.hx:15: Left(Left(String1))
      

      toString()

      function toString():String {
          return Std.string(switch this {
              case Left(Left(v)): v;
              case Left(Right(v)): v;
              case Right(Left(v)): v;
              case Right(Right(v)): v;
          });
      }
      
        2
  •  0
  •   Jeff Ward    6 年前

    我基本上是在尝试创建一个接受类型为的变量的函数 String , Int Float ,或 Bool ...

    overload 图书馆。它是一个允许在Haxe中重载函数的宏。它在编译时根据输入的类型决定调用哪个函数。它比 haxe.ds.Either (又名 Left / Right

        3
  •  0
  •   0x.dummyVar    6 年前

    using Type;
    
    class Multimorph {
    
        public static inline function value ( value : AnyAny ) {
            return value.enumParameters () [ 0 ];
        }
    
        public static inline function position ( value : AnyAny ) {
            return value.enumIndex ();
        }
    
    }
    
    typedef Any2 = Of2<Dynamic, Dynamic>;
    typedef Any3 = Of3<Dynamic, Dynamic, Dynamic>;
    
    enum About2 <A, B> {
        PosA ( value : A );
        PosB ( value : B );
    }
    enum About3 <A, B, C> {
        PosA ( value : A );
        PosB ( value : B );
        PosC ( value : C );
    }
    
    abstract Of2 <A, B> ( About2<A, B> ) from About2<A, B> to About2<A, B> {
        @:from static inline function from_A <A, B> ( val : A ) : Of2<A, B> return About2.PosA ( val );
        @:from static inline function from_B <A, B> ( val : B ) : Of2<A, B> return About2.PosB ( val );
        @:to inline function to_A () : Null<A> return switch ( this ) { case About2.PosA ( val ): val; default: null; }
        @:to inline function to_B () : Null<B> return switch ( this ) { case About2.PosB ( val ): val; default: null; }
    }
    abstract Of3 <A, B, C> ( About3<A, B, C> ) from About3<A, B, C> to About3<A, B, C> {
        @:from static inline function from_A <A, B, C> ( val : A ) : Of3<A, B, C> return About3.PosA ( val );
        @:from static inline function from_B <A, B, C> ( val : B ) : Of3<A, B, C> return About3.PosB ( val );
        @:from static inline function from_C <A, B, C> ( val : C ) : Of3<A, B, C> return About3.PosC ( val );
        @:to inline function to_A () : Null<A> return switch ( this ) { case About3.PosA ( val ): val; default: null; }
        @:to inline function to_B () : Null<B> return switch ( this ) { case About3.PosB ( val ): val; default: null; }
        @:to inline function to_C () : Null<C> return switch ( this ) { case About3.PosC ( val ): val; default: null; }
    }
    

    看起来效果不错,但你得打电话 Multimorph.value ( v : AnyAny )

    using Multimorph;
    
    class Main {
    
        static function main () {
            trace ( func ( "Hello World!") );
        }
    
        static function func ( arg : Of2<Int, String> ) {
            if ( arg.position () == 0 ) {
                return 'Was Passed an Integer `${ arg.value () }`';
            } else {
                return 'Was Passed a String `${ arg.value ()}`';
            }
        }
    
    }
    

    Here's a script 这将产生更大的多形态软件包。