2021年6月27日日曜日

Goの値レシーバーの使いどころがわからない

Goでクラスっぽいものを実装するときにレシーバーを使うわけですが、これは値レシーバーとポインターレシーバーの2種類があるそうな。

で、何度調べても値レシーバーの使いどころがわからない

挙動の違いについて

挙動の違いはわかってるんですよ。要するに値渡しとポインター渡しの違いで、値渡しだとアレがソレになるってことくらいは。

その上で、やっぱり使いどころがわからない。まず値をコピーしないとアカンからサイズがでかいとパフォーマンスに影響が出るし、フィールドの値を変更できない。

フィールドを変更したくないときに使えなくもないわけですが、むしろわかりにくいとしか思えない

たとえばTypeScriptでこんなコードがあったとして・・・

class Foo {
    public bar: number;

    constructor() {
        this.bar = 0;
    }

    baz() {
        this.bar = 1;
    }
}

どう考えてもbaz()をコールしたらbarの値は1になるじゃないですか。実際なるんですけど。

で、値レシーバーを使ってメソッドを定義するとこうなるわけです。

type Foo struct {
	Bar int
}

func (f Foo) Baz() {
	f.Bar = 1
}

パッと見て、どう考えてもBaz()の中でBarの値を変更したがっているようにしか見えないじゃないですか。実際は変更されないんですけど、これが意図した挙動なのかポインターレシーバーにし忘れているのかわからない。もし意図した挙動なら、他人(&将来の自分)が間違えないためにはコメントとして残すしかないわけです。

そもそもの話

そもそもフィールドの値を変更したくないなら普通は代入なんかしないわけで、一時的に別の値にしたければローカル変数にコピーしてそちらを変更しますよね普通。

わざわざ値レシーバーなるものを言語仕様として用意しているからには何かしら有用な場面があるんじゃないかとは思っているんですが、想像力に乏しいせいか有用な使い方が思いつかないので詳しい方の情報もとむ。

0 件のコメント:

コメントを投稿