💡
Zigのunionを使って他の言語のinterface相当のことを行う方法
読み書きする対象としてファイルとメモリ中のバッファとを統一的に扱いたい
Zigで書く練習としてtftp_clientを書いています。
これをコマンドとして使うときにはファイルに対して読み書きを行いますが、ライブラリとして使うときには[]u8
のバッファに対して読み書きできるほうが便利です。これを統一的に扱う方法はあるでしょうか。
Golangだったらio.Reader
, io.Writer
のinterfaceを使う場面です。
std.io.StreamSource
ちょうどぴったりのものを標準ライブラリの中から見つけることができました。
std.io.StreamSource
file descriptor の代わりにこれを引数にとるようにすれば、呼び出す方でファイルにするか[]u8
のバッファにするか選ぶことができます。
これを使って以下のような関数を書いてみました。
fn copy(dst: *io.StreamSource, src: *io.StreamSource) !usize {
このcopy
を使って、buf -> file, file -> buf のコピーをテストしました。
std.io.StreamSource の実装を見てみる
StreamSourceの実態はフィールドを一つだけ持つunionです。
以下のようにメソッドが定義されていて、buffer
, const_buffer
, file
のそれぞれごとのメソッドを呼び出すようにswitch文を使って委譲されています。
要するに、unionを定義して、委譲するメソッドを書けば他の言語のinterface相当を実現することができます。
switch文の分岐が全て同じ場合には inline else
を使って記述を簡略化することができます。以下のページが参考になります。
Discussion