ルール
- AIの書いた文章ではなく自分で書くこと
- AIから教えてもらったことをそのまま鵜呑みにしないで、必ず他の情報(一次情報かどうかは問わない)も調べた上で記述すること
- 可能な限り、経験として得た知識について記載すること。事後的に経験として得たものでも可とする
Goの型について
最近Goを本格的に勉強し始めた。これまでGoで何かアプリケーションを開発した経験はあるが、基礎から勉強をし直すということでA Tour of Goを取り組んだ。その中で、Goのinterfaceについて面白かったのでまとめることにした。
interface
Goではinterfaceは公称型ではなく構造的部分型として扱われる。一方、structは公称型として扱われる。 また、interfaceは明示的に準拠せずとも、型のシグネチャが一致していれば自動的に準拠される。 動的型付け言語におけるダックタイピングのようなことがGoのInterfaceではコンパイル時に保証することができる。
package main
import "fmt"
type Movable interface {
move(spped int)
}
type Vehicle struct {
}
func (*Vehicle) move(speed int) {
fmt.Println("Vehicle moves at", speed, "km.")
}
type Trolley struct{}
func (*Trolley) move(speed int) {
fmt.Println("Trolley moves at", speed, "km.")
}
func main() {
var movable Movable = &Vehicle{} // *Vehicleはmove(speed:)を実装しているので自動的にMovableに準拠する
movable.move(30)
movable = &Trolley{} // *TrolleyもVehicleと同様に自動的にMovableに準拠する
movable.move(10)
}
一方、interface{}型という型もGo言語では定義されていて、これはメソッドを一つも持たないinterfaceである。つまり、全ての型はinterface{}に準拠されるので、他の言語でいうany型と同様な扱いになる。
また、Go 1.18からany型がinterface{}のエイリアスとして事前定義された(参考)ので、直感的にany型を利用できるようになった。
嬉しいこと
個人的には、interfaceも定義上は名前があるので公称型(Nominal Type)である方が嬉しいと思う。型がNominalでないと例えば値オブジェクトを実装する際にTypeScriptのようにBranded Typesを実装するように複雑になる懸念があるからだ。 しかし、Goではinterfaceは構造的部分型であるものの、structについては公称型である。 なので、値オブジェクトについてはstructで実装すればシンプルに実装できる。一方、型は暗黙的にinterfaceに準拠するという仕様はメソッドのinterfaceの影響範囲が大きいことを示していると感じるので、今後理解を深めていく中で感覚を掴んでいきたい。