2023/08/19

golang: interfaceの勉強 (2)

使ったことがない interface だが、テストでモックを作ろうとするときはやっておいた方がよさそうだ。

hiro99ma blog: [golang] interfaceの勉強
https://blog.hirokuma.work/2022/02/golang-interface.html


struct

golang には class はないが、struct で似たようなことはできる。
こういう意味が無いこともできる。

type Abc struct {}

func (a *Abc) Greet() {
  fmt.Println("Hello")
}

ここの「(a *Abc)」の a はレシーバーと呼ばれる。 class の this なんかに近いし、もし Abc の定義に変数があったなら a.xxx のようにしてアクセスできる。

そして Greet() はメソッドである。おそらくだが、レシーバーがない func は関数と呼んで、レシーバーがある func はメソッドと呼ぶんじゃないだろうか。まあ、C++とかでもそういう使い分けだったと思うし、一般的な呼び方をしておいてよさそうだ。
ちなみに構造体のメンバーは「フィールド」と呼ぶ。

この Greet() はAbc を参照しているわけではないし、そもそも Abc はフィールドを持つわけではないので関数であっても困らない。空の構造体はどういうシーンで使うんだろうか?
思いつくのはチャネルの待ち合わせだ。

hiro99ma blog: [golang] chan で待つ
https://blog.hirokuma.work/2022/06/golang-chan.html

この記事では type を使わず直接 struct {} を使っているが、待ち合わせるチャネルが複数ある場合はそれぞれに type で名前を付けることになるだろう。

それ以外だと・・・特に共通で使うような変数がないけど機能としてまとめておいた方がわかりやすいがパッケージにするほどでもないようなときにグループ化する目的とか?

 

struct は既に定義してある struct を中に組み込むことができる。
このとき、その構造体にフィールド名を付けることもできるし、付けないこともできる。付けた場合は他のフィールドと同じようにドットを使って名前を使って参照する。名前を付けなかった場合はあたかも組み込んだ struct のフィールドがそこに展開されているかのように扱うことができる。

なので、こういう組み込みにした場合は軽い継承関係のようなものができているのかと思っていたのだが、キャストのようなことをして代入することはできないそうだ。unsafe とか使ってやってみようとしたのだが、どうにもダメだった。

 

そう、ダメだったのだ。
だからモックにしたい struct を組み込んだ struct を作ってテストしよう、というのはできないのだ。
そういう場合は interface を使うようにするそうである。

・・・というつもりで書こうとしていたのだが、「モックのためだけに interface を使うのってどうなのよ」みたいな記事も見つけてしまい、ちょっと揺らいでいる。

テストのためだけに`interface`を書きたくないでござる — KaoriYa
https://www.kaoriya.net/blog/2020/01/20/never-interface-only-for-tests/

ただまあ、めんどうになるくらいだったら interface を作ってもいいかなというくらいの気持ちだ。C言語でヘッダファイルを書くような感じで。

ちなみに↑の記事の方は、同じ struct 名を用意し、テストの時と本番用でビルドタグを切り替えて読み替える、というようなことをやっている。ビルドタグという機能を知らなかったのだが、ファイル単位で指定できるのは便利そうだ。

 

長くなったので interface については次回。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。