teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

タイポ修正

2020/11/24 00:45

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -39,7 +39,7 @@
39
39
  - インターフェース型に入れたポインタをデリファレンスするには一旦ポインタ型にタイプアサーションが事前に必要
40
40
  - インターフェース型に入れた値のポインタを得るには一旦値型にタイプアサーションかつ変数への束縛が事前に必要
41
41
  - 「インターフェース型へのポインタ」はインターフェース型として機能しない
42
- - 値型をポインタ型に変換するには事前に変数への束縛が必要
42
+ - 値型をポインタ型に変換するには事前に変数への束縛が必要
43
43
  - なので値型から直接ポインタ型レシーバのメソッドを呼ぶことはできない
44
44
  - 逆にポインタ型から値型レシーバのメソッドは呼ぶことができる(低コストでポインタを値に変換できるから)
45
45
 

4

修正

2020/11/24 00:45

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -37,7 +37,10 @@
37
37
 
38
38
  - 「インターフェース型」は「値型とポインタ型」とは別の概念です(双方を格納できる特殊型)
39
39
  - インターフェース型に入れたポインタをデリファレンスするには一旦ポインタ型にタイプアサーションが事前に必要
40
- - インターフェース型に入れた値のポインタを得るには一旦値型にタイプアサーションが事前に必要
40
+ - インターフェース型に入れた値のポインタを得るには一旦値型にタイプアサーションかつ変数への束縛が事前に必要
41
41
  - 「インターフェース型へのポインタ」はインターフェース型として機能しない
42
+ - 値型をポインタ型に変換するには事前に変数への束縛が必要
43
+ - なので値型から直接ポインタ型レシーバのメソッドを呼ぶことはできない
44
+ - 逆にポインタ型から値型レシーバのメソッドは呼ぶことができる(低コストでポインタを値に変換できるから)
42
45
 
43
46
  この辺りのルールはコードを書く側にとって統一感がないように見えますが、これらを気の利いたコード生成などで隠さないのがGo言語の特徴のひとつです。(書き手の好みで書き方に揺れが起こりにくい)

3

質問の意図を誤解していたため、追記

2020/11/24 00:44

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -3,4 +3,41 @@
3
3
  しかし、「構造体型」と「構造体へのポインタ型」はあくまで別の型なので
4
4
  型互換チェックでは単純に「そのインターフェース型のメソッド一覧」と「対象の型のメソッド一覧」との比較検証のみを行います。わざわざ複数の型との比較は行いません。
5
5
 
6
- なぜそうなのかの境目はおそらくですが、コンパイル後のメモリ効率と融通効かせるメリットのトレードオフです。前者の自動参照はそれをするかしないかでメモリコストほぼ変わらないのですが、後者の場合、2つの型情報をマージした型情報を別途残す必要があります。
6
+ なぜそうなのかの境目はおそらくですが、コンパイル後のメモリ効率と融通効かせるメリットのトレードオフです。前者の自動参照はそれをするかしないかでメモリコストほぼ変わらないのですが、後者の場合、2つの型情報をマージした型情報を別途残す必要があります。
7
+
8
+ ## 追記
9
+
10
+ やはりエラーメッセージを示して欲しかったところ。
11
+
12
+ エラーメッセージは
13
+ ```
14
+ cannot use xy (type XY) as type XYInterface in assignment:
15
+ XY does not implement XYInterface (Five method has pointer receiver)
16
+ ```
17
+ 前述の回答は質問者の意図とは少しずれていたようです。
18
+
19
+ - 「構造体へのポインタ型」であれば「XYInterface」に代入でき、意図した操作が可能
20
+ - 「構造体型」の場合「XYInterface」に代入できず上記のエラーとなる
21
+
22
+ という状況の説明が欲しいということですね。ポインタ型は「*」による参照をとるだけで「構造体型」との互換が取れるのに対し、「構造体型」の場合、構造体型のメソッドレシーバーはメソッドが呼ばれる際、構造体のコピーを伴い特定のメモリアドレスに存在する保証がありません。なので「&」によるポインタに変換できません。
23
+ ポインタを得るには必ず変数への束縛が必要になります。
24
+
25
+ 質問の後半に書かれた「XYInterface型へのポインタ」は「インターフェース型に入れられた値へのポインタ」と誤解しないでください。あくまで「XYInterfaceというインターフェース型へのポインタ」です。
26
+ ```go
27
+ var i XYInterface
28
+ xy := XY{1, 2}
29
+ i = xy
30
+ i.Ten()
31
+ (&i).Five()
32
+ ```
33
+
34
+ Go言語では「インターフェース型へのポインタ」はインターフェースではなくなりますのでメソッドを呼ぶことはできなくなります。通常、Go言語でインターフェース型へのポインタを使う場面は引数で渡したインターフェース型に結果を入れるときだけです(引数で結果受け取り)。
35
+
36
+ まとめると、
37
+
38
+ - 「インターフェース型」は「値型とポインタ型」とは別の概念です(双方を格納できる特殊型)
39
+ - インターフェース型に入れたポインタをデリファレンスするには一旦ポインタ型にタイプアサーションが事前に必要
40
+ - インターフェース型に入れた値のポインタを得るには一旦値型にタイプアサーションが事前に必要
41
+ - 「インターフェース型へのポインタ」はインターフェース型として機能しない
42
+
43
+ この辺りのルールはコードを書く側にとって統一感がないように見えますが、これらを気の利いたコード生成などで隠さないのがGo言語の特徴のひとつです。(書き手の好みで書き方に揺れが起こりにくい)

2

補足

2020/11/24 00:35

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -1,5 +1,6 @@
1
1
  フィールドやメソッドの解決の時だけ気の利いた参照型か非参照型かに関わらず対象にアクセスが可能になってはいますが、それはその場の情報だけでコード生成できるから便利に自動で振り分けされます。
2
2
 
3
3
  しかし、「構造体型」と「構造体へのポインタ型」はあくまで別の型なので
4
- 型互換チェックでは単純に「そのインターース型のメソッド一覧」と「対象の型のメソッド一覧」との比較検証のみを行います。
4
+ 型互換チェックでは単純に「そのインターフェース型のメソッド一覧」と「対象の型のメソッド一覧」との比較検証のみを行います。わざわざ複数の型との比較は行いません。
5
+
5
- わざわざ複数との比較いません
6
+ なぜそうなかの境目はおそらくですが、コンパイル後のメモリ効率融通効かせるメリットトレードオフです。前者の自動参照それをするかしなかでメモリコストほぼ変わらないのですが、後者の場合、2つの型情報をマージした型情報を別途残す必要があり

1

補足

2020/11/22 03:01

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -1,4 +1,5 @@
1
1
  フィールドやメソッドの解決の時だけ気の利いた参照型か非参照型かに関わらず対象にアクセスが可能になってはいますが、それはその場の情報だけでコード生成できるから便利に自動で振り分けされます。
2
2
 
3
3
  しかし、「構造体型」と「構造体へのポインタ型」はあくまで別の型なので
4
- 型互換チェックでは単純に「そのインターエース型のメソッド一覧」と「対象の型のメソッド一覧」との比較検証のみを行います。わざわざ複数の型との比較は行いません。
4
+ 型互換チェックでは単純に「そのインターエース型のメソッド一覧」と「対象の型のメソッド一覧」との比較検証のみを行います。
5
+ わざわざ複数の型との比較は行いません。