feature image

2021年12月10日 | ブログ記事

Go(golang)のinterfaceを†完全理解†した

この記事はtraP Advent Calendar 2021 27日目の記事です。

この記事は「interface何も分からん」ってなっている人が、ざっくりinterfaceの気持ちを理解するために書かれています。よって正確性に欠けることがあります。

目次

1.はじめに
2.例
3.コードの解説
4.実行の流れ
5.この例を踏まえて
6.疑問
7.結論


あなたは誰? : いろり(@irori)。sysAd班,グラフィック班
できること : golang,mysql(諸説あり)
できないこと : フロントエンド全般


はじめに

golangのコードを読むとちょくちょくインターフェイスが出てきます。
ここでインターフェイスの理解が中途半端だと、コードの意味を見失ったりします(n敗)。
iroriは部内イベント管理サービスであるknoQのバックエンドを担当しているのですが、knoQ進捗会でのfuji先輩とwasabi先輩のinterfaceの説明がわかりやすかったので、残しておきたいと思います。


//Circle(円)という構造体を定義 *1
type Circle struct {
    Radius int
}

//Circleのメソッドを定義 *2
func (c Circle) GetArea() int {
    return 3 * c.Radius * c.Radius
}

//Square(正方形)という(ry 
type Square struct {
    Height int
}

func (s Square) GetArea() int {
    return s.Height * s.Height
}

//Figure(図形)インターフェイスを定義 *3
type Figure interface {
    GetArea() int
}

//Figureの面積を表示する関数を定義 *4
func DisplayArea(f Figure) {
    fmt.Printf("面積は%vです\n", f.GetArea())
}

//実行される部分 *5
func main() {
    circle := Circle{Radius: 1}
    DisplayArea(circle)
    
    square := Square{Height: 3}
    DisplayArea(square)
}

コードの解説

*1

circleという構造体を定義している。
構造体とクラスはほぼ同じと考えていいと思う。RPGの村人クラスだったら、年齢と性別があるのと同じように、円クラスは半径という数値を持つ(と定義している)。
(型と同様に考えても良いと思う。つまりint型、string型、circle型という感じ)

*2

円クラスのメソッドを定義している。これは円の面積を求めるメソッド。
メソッドは円クラスのもののみが使える関数というイメージでオッケー。

Square(正方形)も同様です。

*3

インターフェイスを定義している。
書き方はこう。

type 名前 interface {
    メソッド メソッドでreturnされる型
}

意味は「Figureというのは引数なし,返り値intのメソッドGetArea()を持つインターフェイスです」ということ。
「なぜメソッドなのか?」、「どういう意味があるのか?」は後述。

*4

Figureインターフェイスのみで使える関数を定義している。引数はインターフェイス。
(正確にはインターフェイスの条件を満たすクラスの何かです)

*5

goではファイルを実行した時に
func main(){}の {} の中が実行されます。(ド基礎。よく忘れる...)
つまりここが実行される場所。

circle := Circle{Radius: 1}

ではCircle型(クラスの意)のcircleが作られている。そしてそのcircleには半径1が代入されている。
(RPGを例に出すと村人型の村人Aが作られ、年齢15歳が代入されているイメージ。)

DisplayArea(circle)

ではcircleの面積が計算され、「面積は3です」と表示されます。

実行の流れ

前提

  1. circleはCircle型
  2. Circle型はメソッドGetArea()を持つ。よってFigureインターフェイスに含まれる
  3. Figureインターフェイスに含まれるのでDisplayArea()が実行できる

🆗

処理

circle := Circle{Radius: 1}

で半径1のcircleが作成される

  1. DisplayArea(circle)では、関数DisplayAreaが呼び出され
fmt.Printf("面積は%vです\n", circle.GetArea())

が実行される

circle.GetArea()

は(circleの半径が1だったから)面積の計算結果3とが返却される

fmt.Printf("面積は%vです\n", 3)

になるから「面積は3です」と表示される

この例を踏まえて

同じメソッドを持つ型に共通する関数を作りたいんだなー とわかればOK

つまりGetArea() がラベルのような働きをしている!

GetArea()を持つ型のみが関数DisplayArea を実行できるよ〜 ということ。

そして、「GetArea()を持つ」という条件をFigureインターフェイスといいます。(ちょっとざっくり言いすぎかもしれない)

疑問

何でメソッドをラベルに代わりにするんだ? ラベルみたいなものを直接定義すればよくないか?

つまり

Q.

ラベル@Figure が貼ってある型はDisplayArea を実行できる

みたいにした方がスマートだし、柔軟性が効くのでは?

A.

例えば@Figureがあり、@Figureがついている型に実行できる関数があったとしよう。
その時にその関数は何ができるだろうか?

@Figureは何らかのメソッドを持つことを保証するものではないので、@Figureの全てで 〜ができるという保証がない

逆に、GetArea()のメソッドを持つ型をFigureインターフェイスとすれば、Figureインターフェイスは少なくともGetArea()を使用できることが保証されている


つまり、

interfaceで呼び出された関数は,interfaceで定義されたメソッドを使うことを基本的に前提としている

interfaceは(意味由来)やりたいことから作られている

のである!

(とiroriは理解した)


次(今日)の担当はiroriさんです。お楽しみに〜(???)
明日の担当はryohaさんです。楽しみ〜

irori icon
この記事を書いた人
irori

グラフィック班とsysAd班(とサウンド班)で活動しています

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2021年12月8日
C++ with JUCEでステレオパンを作ってみた【AdC2021 26日目】
liquid1224 icon liquid1224
2021年5月16日
CPCTFを支えたインフラ
mazrean icon mazrean
2021年11月25日
【一人カラオケ活用術】安く済ませるボーカルレコーディング【AdC2021 13日目】
liquid1224 icon liquid1224
2021年11月24日
クリスマスデートをしよう!!!
mera icon mera
記事一覧 タグ一覧 Google アナリティクスについて