Go構造体でデフォルト値を設定する方法


143

以下の質問には複数の回答/テクニックがあります。

  1. golang構造体にデフォルト値を設定するにはどうすればよいですか?
  2. golangで構造体を初期化する方法

いくつか回答がありますが、さらに議論が必要です。



@iczaあなたの答えはそれを行う方法を提供しますが、質問のタイトルで行くと、非常に具体的な質問であるため、類似したり検索したりすることはできません。私は私の答えにリンクを追加します。
Prateek、2016年

ここには2つの質問があります。1つ選んでください。(質問のタイトルに従って)最初の質問を選択すると仮定して、以前の調査についてより具体的に説明し、他の回答でより多くの議論が必要な場合は、具体的に説明してください。
ダンカンジョーンズ

回答:


96

考えられるアイデアの1つは、別個のコンストラクター関数を作成することです。

//Something is the structure we work with
type Something struct {
     Text string 
     DefaultText string 
} 
// NewSomething create new instance of Something
func NewSomething(text string) Something {
   something := Something{}
   something.Text = text
   something.DefaultText = "default text"
   return something
}

6
はい、これは私の回答でも述べた方法の1つですが、この機能のみを使用するように強制することはできません。
Prateek、2016年

@Prateekそれはこれか、醜くて複雑すぎるインターフェイスを使用しています。
OneOfOne 2016年

31
@Prateekはい、単純に型自体をエクスポートしない場合は、このコンストラクタを使用するように強制できます。関数NewSomethingやフィールドText、をDefaultTextエクスポートできますが、構造体タイプはエクスポートしないでくださいsomething
アミットクマールグプタ2016年

1
問題はさらに悪化します...サードパーティ(ライブラリなど)を使用して(reflect.New()たとえばを介して)構造体をインスタンス化する場合、特別な名前のファクトリ関数について知ることはできません。その場合、言語自体が変更されない限り、インターフェース(ライブラリーがチェックできる)だけが機能すると思います。
エダム

1
デフォルトを設定するのは良いことですが、デフォルトをオーバーライドしたい場合があります。この場合、デフォルトではない値で構造体を初期化することはできません。私にとって少し迷惑です
Juliatzin

68
  1. メソッドに構造体を取得するよう強制します(コンストラクターの方法)。

    優れた設計は、型をエクスポートされないようにすることですが、構造体/型を適切に初期化できるNewMyType()のようなエクスポートされたコンストラクター関数を提供します。また、具象型ではなくインターフェース型を返します。インターフェースには、他のユーザーがあなたの値で実行したいすべてのものが含まれている必要があります。そして具体的な型はもちろんそのインターフェースを実装する必要があります。

    これは、型自体をエクスポートしないようにするだけで実行できます。関数NewSomethingとフィールドTextおよびDefaultTextをエクスポートできますが、構造体タイプはエクスポートしないでください。

  2. 独自のモジュール用にカスタマイズするもう1つの方法は、Config構造体を使用してデフォルト値を設定することです(リンクのオプション5)。


7
これは現在、リンク切れです(404):joneisen.tumblr.com/post/53695478114/golang-and-default-values
Victor Zamanian

3
ウェイバックマシンで使用できます。
n8henrie

FWIW、私はそれが「オプション3」だと思います-少なくともウェイバックマシンリンクでは。(「オプション5」はありません)。
decimus phostle 2018年

@ m90 golintを沈黙させるには、パブリックインターフェイスタイプを返すように関数を宣言できます
Thomas Grainger

@ThomasGrainger私のコメントはこの回答の以前のリビジョンを参照しているようですが、これは本当にこのような意味がありません:)私はそれを削除します。
m90

32

Victor Zamanianからの回答のオプション1の1つの問題は、型がエクスポートされない場合、パッケージのユーザーはそれを関数パラメーターなどの型として宣言できないことです。これを回避する1つの方法は、 struct eg

package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
    Name string
    Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
    return candidate{name, 0}  // enforce the default value here
}

これにより、エクスポートされたCandidateインターフェイスを使用して関数パラメーターの型を宣言できます。このソリューションからわかる唯一の欠点は、すべてのメソッドをインターフェイス定義で宣言する必要があることですが、いずれにしてもそれは良い習慣であると主張できます。


New関数を呼び出した後、Name変数とVotes変数を変更できますか?
morteza khadem

シンプルな例です。

小さなタイプミス:Votes unit32おそらくVotes uint32
PartyLich

@PartyLichはよく見つかりました。修正する必要があります。
wolfson109

13

これをタグで行う方法があり、複数のデフォルトを使用できます。

次の構造体があり、2つのデフォルトタグdefault0およびdefault1があるとします。

type A struct {
   I int    `default0:"3" default1:"42"`
   S string `default0:"Some String..." default1:"Some Other String..."`
}

これで、デフォルトを設定することができます。

func main() {

ptr := &A{}

Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...

Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}

ここだ遊び場での完全なプログラムを

スライスやマップなど、より複雑な例に興味がある場合は、creasty / defaultseを見てください。


どうもありがとう!ライブラリが提案したのと同じコードを書き始め、この投稿に出くわしました。期待どおりに動作します(github.com/creasty/defaults)。値がない場合はデフォルトが設定されますが、変数に値を割り当てた場合は、デフォルトが割り当てられません。これはyaml.v2ライブラリとうまく連携します。
Nordes

3

https://golang.org/doc/effective_go.html#composite_literalsから:

パッケージosから派生したこの例のように、ゼロの値では不十分で、初期化コンストラクターが必要な場合があります。

    func NewFile(fd int, name string) *File {
      if fd < 0 {
        return nil
      }
      f := new(File)
      f.fd = fd
      f.name = name
      f.dirinfo = nil
      f.nepipe = 0
      return f
}

-3
type Config struct {
    AWSRegion                               string `default:"us-west-2"`
}

1
これは誤りです。せいぜい、そのフィールドにタグ値を設定してリフレクションでその値に到達することができますが、それでも構文は正しくなく(ティックが欠落)、文字列型のデフォルト値しか設定できません。この例が具体的に何を参照しているかについて洞察がある場合は、参照するリンクを追加してください。
markeissler 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.