2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

golangのinterface

Posted at

interface がよくわからん

interface を英和辞典で調べると境界面、接点、共通の問題と出てくる。
コンピューター用語辞典によると

インタフェースは,実装についての情報をもたないメソッドの集合の宣言とする.
インタフェース及び継承をサポートするオブジェクトシステムでは,
インタフェースは,一般に他のインタフェースから継承できる

ここからはコードを用いて go のコードを使いながら interface の理解を進める。

interface のメソッドを満たしていれば異なる構造体でも interface に代入できる。

1

main.go
type Hoge interface {
	FuncA()
	FuncB()
}

type Foo struct {
    x string
    y int
    z bool
}

上記のコードの Hoge インターフェイスは FuncA、FuncB という関数を持った集合体 = メソッドの集合体
実装部分は Foo が担っている。
実装:Foo
インターフェイス:Hoge
まず初めに実装部分の Foo にメソッドを定義する

main.go
func (f *Foo) FuncA() {}
func (f *Foo) FuncB() {}

Hoge インターフェイスが持っているメソッドと同じ名前のメソッドを構造体 Foo に実装する。
ここで Hoge と Foo の関係が生まれる。
ここからインターフェイスがどういう役割を果たすかを考えていく。

main.go
package main

type Hoge interface {
	FuncA()
	FuncB()
}

type Foo struct {
	x string
	y int
	z bool
}

func (f *Foo) FuncA() {}
func (f *Foo) FuncB() {}

func hogehoge(d Hoge) {
	d.FuncA()
	d.FuncB()
}

func main() {
	var hoge Hoge
	hoge = &Foo{} // 型はHoge
	hogehoge(hoge)

	foo := &Foo{} // 型はFoo
	hogehoge(foo)
}

hogehoge という新しい関数を追加した。hogehoge は引数に型 Hoge を受け取る。
main 関数に hoge と foo 二つの変数を用意し関数 hogehoge の引数に入れる。
ここで注目してほしいのが、変数 hoge と変数 foo はそれぞれ異なる型を持った変数であるが、
どちらもエラーは起きない。ここでもうひとつ新しい構造体を追加する。

main.go
package main

type Hoge interface {
	FuncA()
	FuncB()
}

// foo struct
// foo method

type HogeFoo struct {
	a string
	b string
	c string
}

func (h *HogeFoo) FuncA() {}
func (h *HogeFoo) FuncB() {}

func hogehoge(d Hoge) {
	d.FuncA()
	d.FuncB()
}

func main() {
	var hoge Hoge
	hoge = &Foo{}
	hogehoge(hoge)

	foo := &Foo{}
	hogehoge(foo)

	hogefoo := &HogeFoo{}
	hogehoge(hogefoo)
}

新しく追加した構造体 HogeFoo を持った変数 hogefoo も関数 hogehoge の引数に正しく入っている。
エラーは起きない。つまり、異なる構造体を持っている変数でもひとつの interface を満たしていれば、どちらも同じ interface に代入できる。

構造体の実装と構造体の使用を切り離して考えられる。

最初に新しい interface を追加する。

main.go
package main

// Hoge interface

type Half interface {
	FuncA()
}

// foo struct
// foo method

// HogeFoo struct
// HogeFoo method

func hogehoge(d Hoge) {
	d.FuncA()
	d.FuncB()
}

func half(ho Half) {
	ho.FuncA()
}

func main() {
	var hoge Hoge
	hoge = &Foo{}
	hogehoge(hoge)

	foo := &Foo{}
	half(foo)

	hogefoo := &HogeFoo{}
	half(hogefoo)
}

新しく追加した interface、Half は FuncA だけ持っていて FuncB は持っていない。
構造体 Foo と構造体 HogeFoo は Hoge インターフェイスと Half インターフェイス、どちらも満たしている。
関数 half は Half の型を持った引数を受け取るがこの時引数に変数 foo、変数 hogefoo をそれぞれ入れると FuncA しか使用できなくなっている。
Half インターフェイスは FuncA しか持っていないので当然なのだが、これが interface を使用する有用性なのではないかと推測する。
つまり構造体の使用方法を interface によって明確にでき、構造体にさまざまなメソッドが実装されていたとしても、使用するときには必要なメソッドのみを指定し、使用できるので、不要なメソッドに依存せずに済む。

終わりに

まだ実際に開発などで使用していないので確実に掴めた感覚にはなりませんでしたが、
何となくでも使い方のイメージが掴めました。
この記事が誰かの参考になると嬉しいです。
最後まで読んでいただきありがとうございました。

参考サイト

Golang インターフェース

[Golang]interface は何者だ-Gopher への道 ②

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?