はじめに
Goを使っていると、以下のような 型アサーションエラー に遭遇することがあります。
impossible type assertion: comp.(*ExampleService)
*ExampleService does not implement Component (missing method Name)
このエラーの原因は、インターフェースを満たしていないことですが、Goの型システムを理解していないと解決が難しい場合があります。
1. Goの型アサーションとは?
型アサーションとは、インターフェース型の値を具体的な型に変換する 方法です。
基本的な型アサーション
var i interface{} = "hello"
s := i.(string) // 型アサーション:interface{} を string に変換
fmt.Println(s) // "hello"
このコードでは、i
は interface{}
型ですが、(string)
を使うことで string
型として扱えます。
2. 型アサーションが失敗する場合
型アサーションは、間違った型に変換しようとすると panic を発生 させます。
var i interface{} = "hello"
n := i.(int) // panic: interface conversion: string is not int
fmt.Println(n)
このような panic を防ぐために、Goには 安全な型アサーション の書き方が用意されています。
3. 安全な型アサーションの書き方
Goでは、型アサーションが失敗したときに false を返す方法があります。
var i interface{} = "hello"
s, ok := i.(string) // 型アサーションが成功する場合
if ok {
fmt.Println("変換成功:", s)
} else {
fmt.Println("変換失敗")
}
n, ok := i.(int) // 型アサーションが失敗する場合
if !ok {
fmt.Println("型アサーションが失敗しました") // こちらが実行される
}
4. インターフェースを型アサーションする
Goでは、インターフェースから具体的な型に変換することもできます。
type Component interface {
Name() string
}
type ExampleService struct{}
func (s *ExampleService) Name() string {
return "example"
}
func main() {
var comp Component = &ExampleService{}
// 安全な型アサーション
service, ok := comp.(*ExampleService)
if !ok {
fmt.Println("型アサーション失敗")
return
}
fmt.Println("変換成功:", service.Name())
}
このコードでは、Component
インターフェースを *ExampleService
に変換しています。
ok をチェックすることで、安全に実行できます。
5. 型アサーションの落とし穴
(1) インターフェースを満たしていない場合
type Component interface {
Init() error
}
type ExampleService struct{}
func main() {
var comp Component = &ExampleService{}
service, ok := comp.(*ExampleService) // これはエラー!
if !ok {
fmt.Println("型アサーション失敗")
}
}
この場合、ExampleService
に Init()
メソッドがないため、Component
を満たしていません。
解決策 として、Init()
メソッドを実装する必要があります。
func (s *ExampleService) Init() error {
return nil
}
(2) nil のチェックを忘れる
⚠️ nilチェックしたあとでもpanicする場合があるのでコメントをチェックして下さい
var comp Component
service, ok := comp.(*ExampleService) // これは `nil` になる可能性がある!
comp が nil の場合、型アサーションは false を返しますが、型が一致していると勘違いして nil のまま進んでしまうことがあります。
解決策
if comp == nil {
fmt.Println("comp は nil です")
} else if service, ok := comp.(*ExampleService); ok {
fmt.Println("型アサーション成功")
}
まとめ
- 型アサーションは、インターフェース型の値を具体的な型に変換する方法
-
s := i.(string)
は 失敗するとpanic
する ので注意 - 安全な型アサーション
(s, ok := i.(string))
を使うとok
で成否を確認できる - インターフェースを型アサーションするときは、事前に
nil
チェック も忘れずに