39583


スライスを型宣言してデータベースから自身の情報を取得するメソッドを実装したのですが、メソッド内で確認するとArtistというフィールドの情報が取得できていますが、メソッドの呼び出し元で表示するとArtistフィールドを変更できていません。

[code]

    type Track struct {
        gorm.Model
        Name     string `sql:"not null;unique" json:"name"`
        Phonetic string `json:"phonetic"`
        Artist   Artist `json:"artist"`
        ArtistID uint   `json:"artistId"`
    }
    
    type Tracks []Track
    
    func (ts *Tracks) List(dba *gorm.DB, limit, offset int) error {
        err := dba.Order("created_at desc").Limit(limit).Offset(offset).Find(ts).Error
        if err != nil {
            return err
        }
        newSlice := make(Tracks, len(*ts))
        for i, t := range *ts {
            if err = dba.Model(&t).Related(&t.Artist).Error; err != nil {
                return err
            }
            newSlice[i] = t
        }
        ts = &newSlice
        // ここでTrack内のArtistに情報が入っている。
        log.Println(ts)
        return err
    }
    
    func someFunc(){
        var tracks Tracks
        tracks.List(dba, limit, offset)
        // ここで確認するとArtistが初期化されている。
        log.Println(tracks)
    }
    
[/code]

なぜこのような挙動になるのでしょうか。良い実装方法があれば教えてください。よろしくお願い致します。


CC BY-SA 3.0
2017-11-14T23:55:24.520
39579
2017-11-15T02:47:51.107
7232
question
go
スライスに実装したメソッドでスライスの要素を変更したい。


`List` メソッドのレシーバー `ts` のスコープは `List` 内に限られているので、今回のプログラムで外部変数の書き換えは起こっていません。註
これは、レシーバーであるポインタが指し示す実体がスライスであるかどうかとは関係ありません。

## 詳細

以下の行でレシーバー `ts` にポインタの代入が行われています。

[code]

    ts = &newSlice
    
[/code]

しかしこれはメソッド内にスコープを持つ変数 `ts` を書き換えているだけで、`ts` が指し示している実体 `*ts`
を書き換えてはいません。したがって、以下のように `*ts` を書き換えるようにすると上手くいきます。

[code]

    *ts = newSlice
    
[/code]

## 簡単な例

より問題を簡単にするために、以下のプログラムを用意しました。

[code]

    package main
    
    import "fmt"
    
    type S struct {
        a int
    }
    
    func (s *S) update() {
        // s = &S{1}
        *s = S{1}
    }
    
    func main() {
        var x S
        fmt.Println(x)
        x.update()
        fmt.Println(x)
    }
    
[/code]

メソッド `update()` の実装を切り替えると、2回目の `fmt.Println(x)` で出力される内容が変わることが確認できます。[Go
Playground 上で動かせるようにした](https://play.golang.org/p/WlBb9xj2Yg)ので、お試しください。

* * *

註. Go の仕様の ["Declarations and
scope"](https://golang.org/ref/spec#Declarations_and_scope)
にあるスコープの説明に書いてあります。

> The scope of an identifier denoting a method receiver, function parameter,
> or result variable is the function body.


CC BY-SA 3.0
2017-11-15T02:02:56.690
39583
2017-11-15T02:47:51.107
2017-11-15T02:47:51.107
19110
19110
39579
answer