Help us understand the problem. What is going on with this article?

packageに複数のinitがあるときの挙動

More than 5 years have passed since last update.

http://golang.org/doc/effective_go.html#init
ふと、呼び出される順番が気になったので調べてみました
versionは1.4(.2)

initが呼ばれるときのコードを眺める

https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/go.y

で init 的な文字列を探すと
関数宣言でなんか分岐しているところが

https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/go.y#L1334

src/cmd/gc/go.y#L1325
fndcl:
  sym '(' oarg_type_list_ocomma ')' fnres
  {
    Node *t;

    $$ = N;
    $3 = checkarglist($3, 1);

    if(strcmp($1->name, "init") == 0) {
      $1 = renameinit();
      if($3 != nil || $5 != nil)
        yyerror("func init must have no arguments and no return values");
    }
    if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
      if($3 != nil || $5 != nil)
        yyerror("func main must have no arguments and no return values");
    }

    t = nod(OTFUNC, N, N);

renameinit ?
grepすると

https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/init.c#L17

src/cmd/gc/init.c
/*
 * a function named init is a special case.
 * it is called by the initialization before
 * main is run. to make it unique within a
 * package and also uncallable, the name,
 * normally "pkg.init", is altered to "pkg.init·1".
 */
Sym*
renameinit(void)
{
    static int initgen;

    snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
    return lookup(namebuf);
}

middle dotと連番をsuffixとしてつけたシンボルを探してる(作っている)
middle dotつけるから、普段書いているコードから呼ばれちゃう心配がないのか

そして、すぐ下の方には、実際に呼ばれるinit関数を組み立てているコードがあって
そこでinit·<n>をコールしているみたい

https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/init.c#L26

src/cmd/gc/init.c
/*
 * hand-craft the following initialization code
 *  var initdone· uint8                (1)
 *  func init()                 (2)
 *      if initdone· != 0 {            (3)
 *          if initdone· == 2      (4)
 *              return
 *          throw();            (5)
 *      }
 *      initdone· = 1;             (6)
 *      // over all matching imported symbols
 *          <pkg>.init()            (7)
 *      { <init stmts> }            (8)
 *      init·<n>() // if any           (9)
 *      initdone· = 2;             (10)
 *      return                  (11)
 *  }
 */
static int
anyinit(NodeList *n)
{
...
}

コメントはanyinitの方に付いているけど、実際は更に下のfninitの方でやっている
https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/init.c#L92

なるほろ

package内の複数ファイルにinitがあった場合は?

go build のソースをながめてみると
このへんでcompilerを呼んでいる

https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/go/build.go#L944

src/cmd/go/build.go
    // Prepare Go import path list.
    inc := b.includeArgs("-I", a.deps)

    // Compile Go.
    ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
    if len(out) > 0 {
        b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
        if err != nil {
            return errPrintedOutput
        }
    }

このbuildToolchain.gcに渡されているgofilesの出処を探すと

https://github.com/golang/go/blob/release-branch.go1.4/src/go/build/build.go#L604

src/go/build/build.go
dirs, err := ctxt.readDir(p.Dir)

でpackage directory内のエントリ列挙
からの
なんやかんやテストがあって

https://github.com/golang/go/blob/release-branch.go1.4/src/go/build/build.go#L766

src/go/build/build.go
      p.GoFiles = append(p.GoFiles, name)

されている
そして、ctxt.readDirの実装は↓

https://github.com/golang/go/blob/release-branch.go1.4/src/go/build/build.go#L171

src/go/build/build.go
// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
  if f := ctxt.ReadDir; f != nil {
    return f(path)
  }
  return ioutil.ReadDir(path)
}

ctxt.ReadDir は、コマンドラインでファイル列挙してビルドする場合と
swigのサポート時のintサイズ確認でつかわれているみたいなので
通常のパッケージビルドはioutil.ReadDirでよさそう

ファイル名のascii順ですね

_人人人人人人人人人人人人_
> じゃないかと思ってた <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

1.5が正式に出たら改めてソースを追ってみようと思いますん

astronoka
都内でゾンビを撃つ仕事をしています。
smartdrive
SmartDriveのデータプラットフォームが外部のさまざまなデータやサービスと連携し、新しい移動体験やモビリティサービスの提供など、移動の未来の到来を後押しします。
https://smartdrive.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした