ゆるふわ技術日誌

エンジニア見習いの悪戦苦闘日記

Golang インタフェース型のポインタを扱おうとしてハマった【たすけて】

注:いまいちすっきり解決してないので、誰か知っていたら教えてください。


年末クリーンアーキテクチャの本を読んだので、Golangで実践してみようと思ったら思わぬところでハマったメモ。(クリーンアーキテクチャするならオブジェクト指向の言語でするべきなのでは?というのはあるがGolangの勉強も一緒にしたかったというのが大きい)

簡略化するとこんなコードを書いていた。

package main

// 実際は引数受け取ったり値を返したりする
type SomeRepository interface {
    Create()
    Find()
}

// DBとかの技術的詳細に関わる値を持っているイメージ
type SomeRepositoryImpl struct {
    CollectionName string
}

func (repo *SomeRepositoryImpl) Create() {
    return
}

func (repo *SomeRepositoryImpl) Find() {
    return
}

func CreateSomeRepository() *SomeRepository {
    return &SomeRepositoryImpl{
        CollectionName: "Something",
    }
}

SomeRepositoryという抽象を実装したSomeRepositoryImplというのを作りたい、というあるあるなRepositoryのコード。Repositoryを使う側は技術的詳細であるDBに対する操作がどうなっているかということを知らなくて済む、というやつ。

ところが上記コードはコンパイルエラーになる。

エラーになるのは

func CreateSomeRepository() *SomeRepository {
    return &SomeRepositoryImpl{
        CollectionName: "Something",
    }
}

この関数のSomeRepositoryImplを作っているところで、Cannot use '&SomeRepositoryImpl{ CollectionName: "Something", }' (type *SomeRepositoryImpl) as type *SomeRepositoryというエラーになる。

いろいろ試行錯誤して、散々ハマったが、結局のところ答えはこう。

func CreateSomeRepository() SomeRepository {
    return &SomeRepositoryImpl{
        CollectionName: "Something",
    }
}

関数の返り値の型がポインタ型ではなくなった。どうやらインタフェース型のポインタというのはない?らしい。とりあえずうまくいってしまったので続きをやっていこうかなと思いつつ、これがなぜなのか?というのにすっきりとした答えが出せずにモヤモヤしている。