読者です 読者をやめる 読者になる 読者になる

golang のメソッド名の Must について

golang

https://golang.org/pkg/regexp/#MustCompile

こんな感じで Must が付いているものがある。
Must が付いているものは error を返す代わりに panic を発生させる。

で上記の MustCompile() の説明文の一部が以下。

It simplifies safe initialization of global variables holding compiled regular expressions.

グローバルな変数(package private な変数)を安全に初期化するために利用するらしい。

安全に初期化するってどーゆーことかというと、
package private な変数は main() 実行前に初期化されるので、
以下のように regexp.MustCompile() が panic を起こすような不正なパターンを指定すると、
main() 実行前に panic を起こす。

package main

import (
    "regexp"
    "fmt"
)

var r *regexp.Regexp = regexp.MustCompile(`invalid pattern`)

func main() {
    fmt.Println("hello")
}

main() 実行前に panic を起こす = 安全 ということなんだと思う。

以下のように r が package private な変数じゃない場合は
Xxx() が実行されるまで panic になるかどうかが分からない。

package main

import (
    "regexp"
    "fmt"
)

func main() {
    Xxx()
}

func Xxx() {
    r := regexp.MustCompile(`^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$`)
    fmt.Println(r.MatchString("input"))
}

main() が実行されて、アプリケーションが起動してから気づく可能性があるので、
上記のようなケースでは r を package private な変数にした方がいい。

初期化ってことは init 内で利用してもいーのかなと思う。
以下も main() が実行される前に panic が発生する。

package main

import (
    "regexp"
)

var r *regexp.Regexp

func main() {
}

func init() {
    r = regexp.MustCompile(`^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$`)
}


正規表現のパターンが固定である場合は Unit Test などで
安全性を担保できるが、
Unit Test を書くかどうかは開発体制次第。
言語レベルでそれを担保することはできないので、
golang としては package private な変数に利用しましょうっていうルールになるのかな。

golang の標準パッケージに対して Must で grep してみると、
package private な変数に対して利用しているパターンが多かった。

error をハンドリングするのが面倒だから Must って命名するのはダメってことですね。