摘要如何实现接口?

mep*_*eps 2 haxe interface abstract implements

我有一个通用的接口来描述对输出流的访问,如下所示:

interface IOutput {
    function writeInteger(aValue:Int):Void;
}
Run Code Online (Sandbox Code Playgroud)

我有一个基于标准haxe.io.BytesOutput类的接口的抽象实现:

abstract COutput(BytesOutput) from BytesOutput {
    public inline function new(aData:BytesOutput) {
        this = aData;
    }
    public inline function writeInteger(aValue:Int):Void {
        this.writeInt32(aValue);
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管此抽象确实实现了上面描述的接口,但没有直接引用接口,当我尝试像这样使用它时:

class Main {
    public static function out(aOutput:IOutput) {
        aOutput.writeInteger(0);
    }
    public static function main() {
        var output:COutput = new BytesOutput();
        out(output); // type error
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器将引发错误:COutput should be IOutput。我只能通过使用包装BytesOutput和实现的通用类来解决此问题IOutput

我的问题是如何向Haxe编译器表明抽象实现了该接口。

Gam*_*a11 6

抽象不能实现接口,因为它们是编译时功能,并且在运行时不存在。这与接口冲突,它们确实在运行时存在并且动态运行时检查像Std.is(something, IOutput)必须工作一样。

Haxe还具有一种称为结构子类型化的机制,可以用作接口的替代方法。使用这种方法,不需要显式implements声明,只要某些东西与结构统一就足够了:

typedef IOutput = {
    function writeInteger(aValue:Int):Void;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于抽象的实现方式,抽象与结构子类型也不兼容


您是否考虑过使用静态扩展名?至少对于您的简单示例而言,这似乎是使writeInteger()方法可用于任何对象的完美解决方案haxe.io.Output

import haxe.io.Output;
import haxe.io.BytesOutput;
using Main.OutputExtensions;

class Main {
    static function main() {
        var output = new BytesOutput();
        output.writeInteger(0);
    }
}

class OutputExtensions {
    public static function writeInteger(output:Output, value:Int):Void {
        output.writeInt32(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以将其与结构子类型结合使用,因此writeInteger()可用于具有writeInt32()方法的任何内容(try.haxe link):

typedef Int32Writable = {
    function writeInt32(value:Int):Void;
}
Run Code Online (Sandbox Code Playgroud)