$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

Goで関数の引数に、union型っぽくstruct Aもしくはstruct Bのどちらかを受け取れるようにしたい

Goで関数の引数に、struct Aという型もしくはstruct Bのどちらかを受け取るということをしたかった。interfaceをちゃんと切ってそれに必要なメソッドをAとBに実装することで実現できることを知った上で、あまり丁寧にそういうことをせずにやりたい。

色々調べると、genericsを使うとできるようだ。

package main

import "fmt"

type A struct {
    Field1 int
}

type B struct {
    Field2 string
}

type AorB interface {
    A | B
}

func PrintAorB[T AorB](s T) {
    // Tで受け取ったものをそのままs.(type)とは出来ないので、一旦anyへキャスト
    switch v := any(s).(type) {
    case A:
        fmt.Println(v.Field1)
    case B:
        fmt.Println(v.Field2)
    }
}

PrintAorB(A{Field1: 1})   // -> 1
PrintAorB(B{Field2: "2"}) // -> 2
// PrintAorB(2)           // -> type error

こんな感じにすることでAかBだけを受け付ける引数を実現できた。

またこのやり方で1つ便利に使えそうなユースケースとして、いろんなところで大量に使われている関数があったとして引数を新しい型に変更したい時に、いったん両方の型を受け付けた上で少しずつ変更していき、全部置き換わったら新しい型だけに変更するみたいな手法が取れそうに思った。もちろん関数自体を分けるという手もあるが、こういうやり方もあるんだなと覚えておく。

参考