LoginSignup
3
2

More than 5 years have passed since last update.

Goの関数の戻り値にsliceのポインタを返したくないけど、nilの場合もある時

Posted at

sliceは内部にデータへのポインタを持っており、sliceそのものをポインタで渡すのは冗長であると言われる。他人のコードを見てもsliceのポインタを戻り値で返すケースはあまり見かけない。引数でsliceのポインタを受け取ることはあるけれど。

例としてmapから指定keyの値を[]stringとして返す関数を実装する場合。

func GetArray(mapObject map[string]interface{}, key string) ([]string, error) {
  if mapObject[key] == nil {
     // keyの値がnil、もしくは存在しない場合
     return []string{}, nil
  }
  stringArray, ok := mapObject[key].([]string)
  if ok {
     // 値が[]stringだった場合
     return stringArray, nil
  } else {
     // 値が[]stringでない場合
     return []string{}, errors.New("Invalid value for key. " + key)
  }
}

こうしてしまうと、

  • keyの値がnull、もしくは、keyが存在しない場合
  • keyの値が空配列だった場合

のどちらか区別ができなくなる。前者の場合はerrorを返すこと自体、おかしい気がする。

このようにsliceのポインタを返す方法もある。

func GetArray(mapObject map[string]interface{}, key string) (*[]string, error) {
  if mapObject[key] == nil {
     return nil, nil
  }
  stringArray, ok := mapObject[key].([]string)
  if ok {
     return &stringArray, nil
  } else {
     return nil, errors.New("Invalid value for key. " + key)
  }
}

stringArrayPtr, err := GetArray(mapObject, "key1")
if err != nil {
  // keyの値は[]stringではなかった
} else if stringArrayPtr == nil
  // keyの値はnilだった
} else {
  // keyの値は[]stringだった
  // appendはやfor/rangeは、ポインタではできないので実体を指す必要がある
  *stringArrayPtr = append(*stringArrayPtr, "new string")
  for _, str := range *stringArrayPtr {
    // 何かの処理
  } 
}

この方法なら、keyの値がnilだった時は、nilを返すようになる。しかし、最初に述べたようにsliceのポインタを返すのは冗長であるし、受け手側で実体を参照しないとappendやfor/rangeできないのは混乱をもたらしそうである。

そこでこの案はどうか?

func GetArray(mapObject map[string]interface{}, key string, stringArray *[]string) (bool, error) {
  if mapObject[key] == nil {
     return false, nil
  }
  stringArray2, ok := mapObject[key].([]string)
  if ok {
     *stringArray = stringArray2
     return true, nil
  } else {
     return false, errors.New("Invalid value for key. " + key)
  }
}

var stringArray []stringArray
has, err := GetArray(mapObject, "key1", &stringArray)
if err != nil {
  // keyの値は[]stringではなかった
} else if has {
  // keyの値は[]stringだった
} else {
  // keyの値はnilだった
}

このようにすると、値がnilだった場合とエラーだった場合の区別ができ、かつ、sliceのポインタを返さなくていい。

ちなみにxormというO/Rマッパーライブラリから、この案を拝借しました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2