📦
Go で TypeScript みたいに implements をしたかった話
はじめに
この記事ではGoでTypeScriptのimplementsみたいにインターフェースを保証する方法について説明します。
TypeScriptのimplements
TypeScript ではClassを定義する際に、意図したプロパティやメソッドがすべて含まれていることを保証するために implements を使います。
interfaceで宣言したプロパティやメソッドを implementsしてクラスを定義することで、インターフェースを正しく実装しているかコンパイル時にチェックできます。
例:
interface Cat {
name: string;
age: number;
color: string;
meow(): void;
}
class MyCat implements Cat {
name: string;
age: number;
color: string;
constructor(name: string, age: number, color: string) {
this.name = name;
this.age = age;
this.color = color;
}
meow(): void {
console.log(`${this.name} is meowing!`);
}
}
Go ではどうやってインターフェースを保証する?
Go にはimplementsという宣言はないですが、以下のように書くことで、コンパイル時にインターフェースの実装をチェックできます。
package main
import "fmt"
type Cat interface {
Meow()
}
type MyCat struct {
Name string
Age int
Color string
}
// ここがimplementsと同じようなチェックを実現しています!
var _ Cat = (*MyCat)(nil)
func (c *MyCat) Meow() {
fmt.Printf("%s is meowing!\n", c.Name)
}
var _ Cat = (*MyCat)(nil) の行がポイントです。
仕組み
この1行で何が起きているのか見ていきましょう。
var _ Cat = (*MyCat)(nil)
-
(*MyCat)(nil)は*MyCat型の nil ポインタを作成 - それを
Catインターフェース型の変数に代入しようとする - もし
*MyCatがCatインターフェースを実装していなければ、コンパイルエラーになる -
_(ブランク識別子) を使うことで、実際には変数を使わないことを示す
つまり、この1行があることで:
-
Meow()メソッドを実装し忘れた場合、コンパイル時にエラーが出る - TypeScriptの
implementsと同じように、インターフェースの実装を保証できる
まとめ
Go でインターフェースの実装をコンパイル時にチェックするには、以下のように書きます。
var _ InterfaceName = (*ConcreteType)(nil)
これにより、TypeScript の implements と同じように、コンパイル時に型の安全性を保証できます。
Discussion