2019の9日目の記事です。普段、私たちは何気なくiotaを利用しています。私はiotaを使っていくうちに、「誰が1ずつインクリメントしてくれているんだろう...そもそもiotaってなんなんだろう...」と不思議に思うようになりました。やってインクリメントとされていくんだ?)そのことが気になった私は、iotaがどのようにコンパイラによって扱われるかを調べてみることにしました。念の為、iotaとは何か、おさらいしておきましょう。定数に整数の連番を割り振るために用意された仕組みです。3)そして、iotaは事前宣言済み識別子であり、型なしの数値定数です。iotaは定数であるにも関わらず、0から始まる整数の連番を返し、別のconstではまた0から始まるのでしょうか。本章では、iotaの値がいつどのように決定されるかを説明するために、以下を前提知識として共有します。値が計算されるかを知るためには、コンパイルの流れを知る必要があります。Goコンパイラgcは、大まかにいえば以下の手順に従ってコンパイルを行います。本章では、以後の説明のために、「定数の宣言」の文法と各名称を示します。「定数の宣言」の文法をEBNF形式で表現すると、以下の通りとなります。式のリストつまり、定数の宣言において、それぞれの部分の名前は以下の通りです。それぞれの名称は、このあとの説明で用いますので、覚えておいてください。"baz"ExpressionListConstSpec)「定数の宣言」がASTになるまでソースコードが構文ツリーになるまでここから、本題である「iotaがどのようにコンパイラによって扱われるか」を解説します。結論からいえば、定数の宣言、つまりConstDeclおよびConstSpecが字句解析され、構文解析され、ASTへ変換される過程で、iotaのカウンタがいつ0へリセットされるか、各定数に対してどんな値を返すかが決定されます。syntaxパッケージによって、ソースコードが構文ツリーへ変換されるようすを見てみましょう。機械語を生成まず、gcは、.goファイルごとにsyntaxパッケージのParse関数を呼びます。呼び出されたParse関数は、字句解析をした後、これを構文ツリーへ変換するためにfileOrNil関数を呼びます。fileOrNil関数は、以下の流れに従って処理を行います。File構造体を初期化するFile構造体は、そのファイルで定義されているimport、const、var、typeそしてfuncの一覧を保持するDeclListフィールドを持つパッケージ名を取得するimport文にて指定されているパッケージの一覧をimportDecl関数によって取得し、DeclListへ加えるファイルのトップレベルにある定数、変数、型そして関数の宣言を、それぞれconstDecl、varDecl、typeDecl、funcDeclOrNilによって、Declインタフェースを持つ構造体ConstDecl、VarDecl、TypeDecl、FuncDeclへ変換されます。syntaxパッケージにおける関数の呼び出しConstDecl構造体は「ConstDecl」という名前ではありますが、実際には先程の文法でいうConstSpecを表しています(不思議ですね)。ConstDecl構造体はGroupフィールドを持っていて、このGroupフィールドはそれぞれのConstSpecがどのConstDeclに属するかを保持します。同じConstDeclの中で宣言されたConstSpecがConstDecl構造体に変換された時、Groupフィールドの値が同じになります。他のConstDeclの中で宣言されたConstSpecが変換されたConstDecl構造体とは、Groupフィールドの値が異なります。構文ツリーがASTになるまで次に、gcパッケージによって、構文ツリーがASTへ変換されるようすを見てみましょう。機械語を生成gcパッケージは、syntaxパッケージによって得られたFile構造体を受け取り、Node構造体のツリーへ変換したのち、この木構造をたどって型チェックし、SSA(中間表現)へ変換します。このNode構造体は、Xoffsetという、色々な値を保存しておくためのフィールドを持っています。このXoffsetフィールドこそがiotaの値を保持します。int64また、Node構造体はSetIota関数を持ちます。この関数がNode構造体のXoffsetフィールドにiotaの値を代入しています。x}では、このSetIota関数は、どこから呼ばれるのでしょうか。答えは、ConstDecl構造体をNode構造体へ変換する、constDecl関数です。constDecl関数は、ConstDecl構造体へ変換されたConstSpecを引数に受け取り、これをNodeのリストへ変換します。ConstSpecが属するConstDeclが異なる場合、カウンタを0にリセットします。加えて、Nodeのリストへの変換が終わったあと、カウンタをインクリメントします。構文解析の結果からASTが生成される時に、noder.constDecl関数によって決定されるものかと思われます。本記事に間違いがございましたら、Twitterのリプライにてお知らせ下さると幸いです。拙い記事ですが、ここまでお付き合い頂きありがとうございました。幸翠2019年4月に株式会社ディー・エヌ・エーへ新卒として入社し、GoとVue.jsを書いています。Analyticsを利用しています。