オフィスアワーがそろそろ始まるよ!()

vtable

前節でZenのインタフェースについて学びました。Zenのインタフェースは静的、すなわちコンパイル時にポリモーフィズムを実現する手段です。そのため、次のコードのように実行時に異なる構造体を、1つのインタフェース変数に再代入するコードはコンパイルエラーになります。

test "vtable" {
    var a = SensorA {};
    var b = SensorB {};
    var sensor: Sensor = a;
    sensor = b;
}
error[E02046]: expected 'SensorA', found 'SensorB'
    sensor = b;
             ~

上のコードでsensorの型はSensorと指定しました。しかしコンパイラは、sensorの型がSensorAであり、SensorB型の値を代入しようとしている、というエラーを出力しています。

次のテストコードにある2つのokは、共にパスします。ここからわかることは、sensor_asensor_bとは両方ともSensor型として定義しているにも関わらず、実際の型は、それぞれSensorA型とSensorB型になっていることです。これはコンパイラによる型解決の結果です。

examples/ch06-polymorphism/src/vtable.zen:4:12

test "interface type" {
    var a = SensorA {};
    var sensor_a: Sensor = a;
    ok(@typeOf(sensor_a) == SensorA);

    var b = SensorB {};
    var sensor_b: Sensor = b;
    ok(@typeOf(sensor_b) == SensorB);
}

SensorA型とSensorB型を同じ変数で扱うための方法がvtableです。

vtable変数の定義

vtableの動作確認に使用するSensorインタフェースと、SensorAおよびSensorB構造体を以下に示します。

examples/ch06-polymorphism/src/vtable.zen:14:34

const Sensor = interface {
    fn data() u32;
};

const SensorA = struct {
    latest_data: u32 = 42,
    fn data(self: *SensorA) u32 {
        return self.latest_data;
    }
};

const SensorB = struct {
    latest_data: u32 = 52,
    fn data(self: *SensorB) u32 {
        return self.latest_data;
    }
};

fn data(sensor: Sensor) u32 {
    return sensor.data();
}

vtableは、必ずポインタ型で使用します。*vtableで始まりインタフェース型名が続きます。右辺には構造体インスタンスの参照を取ります。

    var a = SensorA {};
    var sensor: *vtable Sensor = &a;

vtableは実行時に値を書き換えることができます。次のコードでは、SensorASensorBのインスタンスを作成し、vtableの変数sensorを書き換えながら、インタフェースを利用しています。

examples/ch06-polymorphism/src/vtable.zen:36:47

test "vtable" {
    var a = SensorA {};
    var b = SensorB {};

    var sensor: *vtable Sensor = &a;
    ok(sensor.data() == 42);
    ok(data(sensor) == 42);

    sensor = &b;
    ok(sensor.data() == 52);
    ok(data(sensor) == 52);
}

sensor.data()の形式でインタフェースのメンバを利用することもできますし、data(sensor)のようにSensor型を要求する関数への引数として利用することもできます。

vtableの配列

異なる構造体型のインスタンスを*vtable型要素を持つ配列で一元的に扱うことができます。

examples/ch06-polymorphism/src/vtable.zen:49:56

test "array of vtable" {
    var a = SensorA {};
    var b = SensorB {};

    const sensors = [_]*vtable Sensor { &a, &b };
    ok(sensors[0].data() == 42);
    ok(sensors[1].data() == 52);
}

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.