質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

3回答

1530閲覧

Go言語のインターフェースの利点・必要性がイマイチよく分かりません

dam9806

総合スコア21

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2019/05/22 09:42

編集2019/05/22 09:49

Go言語の勉強を初めて5日ほどです。
現在、インターフェースについて勉強中です。

自分でサンプルプログラムを作ってみました。
まずは、以下を見て頂けますでしょうか。

package main import "fmt" type Add struct {} func (x Add) calculate(a int, b int) int { return a+b } type Sub struct {} func (x Sub) calculate(a int, b int) int { return a-b } type Mul struct {} func (x Mul) calculate(a int, b int) int { return a*b } type Div struct {} func (x Div) calculate(a int, b int) int { return a/b } func main() { var a Add var s Sub var m Mul var d Div fmt.Println("和:", a.calculate(7, 2)) fmt.Println("差:", s.calculate(7, 2)) fmt.Println("積:", m.calculate(7, 2)) fmt.Println("商:", d.calculate(7, 2)) }

これをインターフェースを使って書き直したものが以下です。

package main import "fmt" type Calc interface{ calculate(a int, b int) int } type Add struct {} func (x Add) calculate(a int, b int) int { return a+b } type Sub struct {} func (x Sub) calculate(a int, b int) int { return a-b } type Mul struct {} func (x Mul) calculate(a int, b int) int { return a*b } type Div struct {} func (x Div) calculate(a int, b int) int { return a/b } func main() { var a Add var s Sub var m Mul var d Div var calc Calc calc = a fmt.Println("和:", calc.calculate(7, 2)) calc = s fmt.Println("差:", calc.calculate(7, 2)) calc = m fmt.Println("積:", calc.calculate(7, 2)) calc = d fmt.Println("商:", calc.calculate(7, 2)) }

どちらも同じ出力結果となります。
この2つのコードを比べても、インターフェースを使う利点・必要性がイマイチよく分かりません。

インターフェースを使ったコードの方が良いのでしょうか?
あるいはサンプルコードが不適ということはあるでしょうか?

当方、オブジェクト指向の知識・経験は少ないです。
一応、継承・ポリモーフィズについて、さらっとネットで調べはしました。
例えば、こちらのWebページなど
https://qiita.com/Akatsuki_py/items/3e35ba326ff254a6790d
https://teratail.com/questions/60856

ご回答頂けると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Add, Sub, Mul, Divのどれを使うかだけが違う関数を書くとき(例えば計算結果を表示するだけ)
インターフェースがないと引数の型が違うだけの関数を4つ書きますが、
インターフェースがあれば1つで済みます。

余剰計算Modを追加したときに、
インターフェースがないとまた同じような関数が一つ増えますが、
あれば何もせずに済みます。

なのでこのコードだと実感しづらいです。


go

1package main 2 3import "fmt" 4 5 6 7type Add struct {} 8func (x Add) calculate(a int, b int) int { return a+b } 9 10type Sub struct {} 11func (x Sub) calculate(a int, b int) int { return a-b } 12 13type Mul struct {} 14func (x Mul) calculate(a int, b int) int { return a*b } 15 16type Div struct {} 17func (x Div) calculate(a int, b int) int { return a/b } 18 19 20// 型によって作り分ける 21func somethingNiceFunctionAdd(c Add, left int, right int) { 22 fmt.Println(c.calculate(left, right)) 23} 24func somethingNiceFunctionSub(c Sub, left int, right int) { 25 fmt.Println(c.calculate(left, right)) 26} 27func somethingNiceFunctionMul(c Mul, left int, right int) { 28 fmt.Println(c.calculate(left, right)) 29} 30func somethingNiceFunctionDiv(c Div, left int, right int) { 31 fmt.Println(c.calculate(left, right)) 32} 33 34 35func main() { 36 var a Add 37 var s Sub 38 var m Mul 39 var d Div 40 41 // 呼ぶ側も型によって使い分ける 42 somethingNiceFunctionAdd(a, 7, 2) 43 somethingNiceFunctionSub(s, 7, 2) 44 somethingNiceFunctionMul(m, 7, 2) 45 somethingNiceFunctionDiv(d, 7, 2) 46 47} 48

go

1package main 2 3import "fmt" 4 5type Calc interface{ 6 calculate(a int, b int) int 7} 8 9type Add struct {} 10func (x Add) calculate(a int, b int) int { return a+b } 11 12type Sub struct {} 13func (x Sub) calculate(a int, b int) int { return a-b } 14 15type Mul struct {} 16func (x Mul) calculate(a int, b int) int { return a*b } 17 18type Div struct {} 19func (x Div) calculate(a int, b int) int { return a/b } 20 21// ひとつでいい 22func somethingNiceFunction(c Calc, left int, right int) { 23 fmt.Println(c.calculate(left, right)) 24} 25 26func main() { 27 var a Add 28 var s Sub 29 var m Mul 30 var d Div 31 32// 呼ぶ側も区別しなくていい 33 somethingNiceFunction(a, 7, 2) 34 somethingNiceFunction(s, 7, 2) 35 somethingNiceFunction(m, 7, 2) 36 somethingNiceFunction(d, 7, 2) 37 38}

投稿2019/05/23 01:47

編集2019/05/23 23:47
ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dam9806

2019/05/23 08:53

回答ありがとうございます! Modを追加する場合、どちらのソースにもMod用の構造体とメソッドの追加は必要ですよね? また、どちらのソースにもmainにfmt.Println文が必要ですよね? そうだとしたら、私の今のレベルでは、インターフェースの利点・必要性が理解できません。 また、インターフェースのように異なる型を受け付ける仕組みって、ふつうに開発中に必要となってくるものでしょうか? 必要となる機会が少ないのであれば、これを勉強するのを後回しにしようかと思うのですが・・・。
dam9806

2019/05/24 02:13

ozwkさん 改めてコード付きの回答、ありがとうございます! somethingNiceFunctionを入れることで、私のサンプルコードのようなmain関数内での明示的なインターフェース型変数への代入文が無くなっていますね! だいぶ理解が進みました。
guest

0

以下のWebページを見つけました。
https://qiita.com/oahiroaki/items/ff21d9adfb843161d1d8

こちらを見ると、まだ私のレベルでは読解が難しいですが、なんとなくインターフェースの利点が見えてきました。
このサンプルでは、JSONに合わせた構造体を準備しなくても良さそうなので、だいぶスマートに記述できそうです。
今後JSONデータを扱う予定があるので、有用な記事でした。

ネットにどれだけインターフェースを使ったサンプルが落ちているか分かりませんが、できるだけ触れるようにして勉強したいと思います。

クローズさせて頂こうと思います。
ご回答してくれた方々、ありがとうございました!

投稿2019/05/23 22:47

dam9806

総合スコア21

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nobonobo

2019/05/24 01:53

それはバリアント型としての利点でインターフェースとダックタイプの利点とは異なります。 そして構造体を用意せずにJSONを扱うのはGo言語では悪手です。(のちに余計に手間がかかります)
dam9806

2019/05/24 02:16

コメントありがとうございます! 難しい用語が出てきて理解できませんが、構造体を用いるべきなのですね。 まだ実際にJSONを使ったコーディングをしていないので、どのような手間がかかるのか実感できませんが、構造体を使った場合と使わない場合の手間の違いが把握できるよう、勉強したいと思います。
guest

0

サンプルコード的なものを書いてみました
https://play.golang.org/p/TDJTvw-3O_8

インターフェースを実装したストラクトを利用すると便利さがわかるかもしれません

go

1package main 2 3import ( 4 "fmt" 5) 6 7// Human interface 8type Human interface { 9 SayHello() 10} 11 12// Japanese struct 13type Japanese struct { 14 Name string 15 Age int64 16} 17 18// American struct 19type American struct { 20 Name string 21 Age int64 22} 23 24// SayHello void (Japanese) 25func (japanese *Japanese) SayHello() { 26 fmt.Printf("%s(%d):\tこんにちは\n", japanese.Name, japanese.Age) 27} 28 29// SayHello void (American) 30func (american *American) SayHello() { 31 fmt.Printf("%s(%d):\tHello\n", american.Name, american.Age) 32} 33 34func main() { 35 humans := []Human{} 36 37 humans = append(humans, &Japanese{Name: "東京太郎", Age: int64(30)}) 38 humans = append(humans, &American{Name: "Bob", Age: int64(25)}) 39 40 for _, human := range humans { 41 human.SayHello() 42 } 43} 44

投稿2019/05/23 16:47

編集2019/05/24 18:37
teikoku-penguin

総合スコア314

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dam9806

2019/05/23 21:54

回答ありがとうございます! サンプルコードの提示もありがとうございます! ですが、インターフェースの利点・必要性がよくわかりません。 また、ご提示のコードでは、Calcインターフェースを使用しているようには見えなかったので、試しにその宣言部分をコメント化して実行したところ、普通に動きました。 つまり、Calcインターフェースがなくても良い・・・ということではないでしょうか?
teikoku-penguin

2019/05/26 12:48

サンプルコードを修正させて頂きました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問