読者です 読者をやめる 読者になる 読者になる

きょこみのーと

元六本木でGo書いてました。今はVRでGo書いてます。

Go言語でのInterfaceの可視性について

ちょっとハマったのでメモがてらまとめました。

Interfaceも通常のstruct等と同じく先頭が小文字で始まる場合に別パッケージで参照できないという点についてです。

ディレクトリ構成

example
├── factory1
│   └── factory.go
├── factory2
│   └── factory.go
├── main1.go
└── main2.go

外部でinterface実装可能

FactoryインターフェースのCreate(),Register()ともに先頭が大文字でパッケージ外から参照可能なので、別のパッケージでインターフェースを実装することが出来ます。

// example/factory1/factory.go
package factory1

type Factory interface {
    Create()
    Register()
}

// example/main1.go
package main

import "./factory1"

type BarFactory struct {

}

func (h BarFactory) Create() {

}

func (h BarFactory) Register() {

}

var _ factory1.Factory = (*BarFactory)(nil)

func main() {
    f1 := BarFactory{}
    f1.Create()
    f1.Register()
}

外部でinterface実装不可能

Factoryインターフェースと同じパッケージ内で実装したものなら、 外部パッケージから利用可能です。

ポイント

  • register()は先頭小文字で不可視になっているため、外部パッケージからはCreate()しか呼べない
  • register()は先頭小文字で不可視になっているため、外部パッケージではインターフェースの実装ができない
//example/factory2/factory.go
package factory2

type Factory interface {
    Create()
    register() // 別packageから参照不可能
}

type FooFactory struct {

}

func (h FooFactory) Create() {
    h.register()
}

func (h FooFactory) register() {

}

var _ Factory = (*FooFactory)(nil)

// example/main2.go
package main

import "./factory2"

func main() {
    f2 := factory2.FooFactory{}
    f2.Create()

    // ERROR: 不可視なので呼び出せない
    // f2.register()
}

type BazFactory struct {

}

func (b BazFactory) Create() {

}

func (b BazFactory) register() {

}
// ERROR: Factory.register()が不可視なのでinterface実装できない
//var _ factory2.Factory = (*BazFactory)(nil)

おわり

あまりinterfaceを使う機会がなかったので、よくわかってなくてハマりました。

(単に使い方わかってなくて使い所がわかってなかっただけかもしれませんが・・・)

触りながら自己理解したので、もし認識違い等ありましたら指摘いただけると助かります。