3
2

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 5 years have passed since last update.

golang初心者のrubyistがinterfaceについてまとめてみたメモ

Posted at

rubyしか使ったことがないプログラマーがgolangを勉強した時にinterfaceの理解でつまづいたので、勉強したことをまとめてみます。

個人的なメモの要素の方が強いので、みにくいかもしれませんが、それでも役に立つ人もいると思って書きました。

interfaceとは?

  • メソッドの型だけを定義したもの
  • golangのinterfaceは型の一つ
  • stringやint64が関数を持っているように、interfaceで型を宣言してその型に関数を持たせることができる
type <型名> interface {
    メソッド名引数の型, ... 返り値の型, ...
    ..
    ..
}

こんな感じでinterfaceというものを定義することができます。

interfaceを使うとどんなメリットがある?

teratailのこの質問を参考にしました。

package main

import (
    "fmt"
)

// Fooに関する定義
type Foo struct{}

func (f *Foo) Name() string {
    return "Foo"
}

// Barに関する定義
type Bar struct{}

func (b *Bar) Name() string {
    return "Bar"
}

// Namedというinterfaceを定義
// Named interfaceによると、このinterfaceによって
// Name() というメソッドを持つことが強制される。
type Named interface{ 
    Name() string
}

// named.Name()の結果を出力する関数。
// (named Named)となっているので、変数namedがNamed interfaceを
// 実装していることを保証している。
// さらにNamed interfaceによって変数namedがName()メソッドを持つことが
// 保証される。
func CallName(named Named) {
    fmt.Println(named.Name())
}

func main() {
    foo := new(Foo)
    bar := new(Bar)

    CallName(foo)
    CallName(bar)
}

この様に、同一の特徴を持った値(この場合 foo もしくは bar)を共通的に取扱いたい場合に interface を用います。これを Named を使わずやろうと思うとそれぞれの型を引数に持った CallNameFoo もしくは CallNameBar を実装する必要があります。

A tour of Goの例


package main

import (
	"fmt"
	"math"
)


// Abserというinterfaceを定義
type Abser interface {
	Abs() float64
}

func main() {
    // interface typeを持った値は、そのinterfaceにあるメソッドを持っている値ならなんでも持つことができる。
    // ここの例でいうと、Abs()メソッドさえ持っていれば、Abser型として認識されるということ。
	var a Abser
	f := MyFloat(-math.Sqrt2)
	v := Vertex{3, 4}

    // type MyFloatはAbs()を持っているのでa = fとしてもエラーにならない
	a = f  // a MyFloat implements Abser
  // struct VertexはAbs()を持っているのでa = &vとしてもエラーにならない
	a = &v // a *Vertex implements Abser

	// In the following line, v is a Vertex (not *Vertex)
	// and does NOT implement Abser.
	a = v

	fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

interfaceは暗黙的に実装される

package main

import "fmt"

type I interface {
	M()
}

type T struct {
	S string
}

// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I = T{"hello"}
	i.M()
}

A tour of GoのInterfaces are implemented implicitly
をみていた時に、最初は意味がわからなかったのですが、上に書いてあることを理解した後だと、当たり前じゃんくらいの感覚になります。

この例では

type I interface {
    M()
}

となっているので、M()メソッドを持っていさえすればI interfaceを実装していると認識されます。

    fmt.Println(t.S)
}

というメソッドが定義されています。
このメソッドの定義によってtype TがM()を持っていることになるので、同時にinterface Iを実装していることになりますが、それを明示的に宣言する必要はないということを言っています。

interfaceの値は内部的には値と型のタプルとして認識されている

A tour of GoのInterface valuesのところです。

golangのinterfaceは内部的には値と型のタプルとして認識されています。

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

func main() {
    // iという変数をinterface Iで定義
    var i I
    // こうするとここでのiは
    // (&{"Hello"}, 型T)という形で内部的に認識されている。
    i = &T{"Hello"}
}

empty interface

A tour of GoのThe empty interfaceがわからなかったので調べました。
基本的に
Go言語 - 空インターフェースと型アサーション - 覚えたら書く
をみたらわかると思います。

empty interfaceはどんな型の値でも受け取れる関数を作るために利用されます。
例えばfmt.Printのようなもの。


func funcName(any interface{}) {
    ...
}

というふうに記述することでどんな型の値でも受け取れる関数が作れます。

参考にさせていただいたサイト

teratail
【Golang】Golangのinterfaceで知っておくとお得なTips
A tour of Go
Go言語 - 空インターフェースと型アサーション - 覚えたら書く

3
2
0

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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?