https://golang.org/ref/spec の和訳摘要です. 完全性はないです.
Version of Jan 14, 2020
##ソースコードの表現
ソースコードはUTF-8である.
###文字
改行 = LF
unicode文字 = Unicodeの"Letter"
unicode数字 = Unicodeの"Number, decimal digit"
###文字と数字
文字 = unicode文字と"_"
##字句要素
###コメント
プログラム // 行コメント
/* 複数行
コメント */
###トークン
トークンは5種類
- 識別子
- キーワード
- 演算子
- 約物(句読点)
- リテラル
空白(スペース, タブ, CR, LF)は無視される
###セミコロン
セミコロンは文の終りを示す
一行に複数文を書きたいときのみ, 明示的にセミコロンを必要とする
###識別子
識別子は文字始まり, 文字+unicode数字が続く
###キーワード
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
###演算子と約物
+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^=
###整数リテラル
_
を区切り文字として使える. 123_456
0b
で2進, 0o
で8進, 0x
で16進を示す
###小数リテラル
.
が1つ含まれる数字
-
1e+01
: 指数表記 -
0x_1
: 16進 -
0x_1P-16
: 16進+指数表記
###虚数リテラル
整数, 小数の最後にi
をつけると虚数
###Runeリテラル
'Rune'
はUnicodeのコードポイント.
-
'ä'
はUTF-8では0xc3 0xa4だが, RuneではU+00E4
-'\377'
'\x07'
'\xff'
'\u12e4'
###文字列リテラル
"バックスラッシュエスケープされる文字列\n"
`エスケープされない文字列`
##定数
- リテラルは定数
-
unsafe.Sizeof(式)
は定数 -
cap(式)
len(式)
は定数のことがある -
real(複素定数)
imag(複素定数)
は数値定数 -
true
false
真偽値定数 -
iota
整数定数
型名を省略したときのデフォルトは bool
, rune
, int
, float64
, complex128
, string
##変数
変数は静的型付けされる
interface{}
型は任意の値を代入できる
##型
型は配列,構造体,ポインタ,関数,インターフェース,スライス,マップ,チャンネル
###メソッド集合
型はメソッドを持つ
- インターフェースは,そのインターフェスをメソッドとして持つ
- 型
T
は,T
をレシーバにするメソッドを持つ - 型
*T
は,*T
かT
をレシーバにするメソッドを持つ - 構造体が埋め込みフィールドを含む場合,そのメソッドも持つ
###真偽値型
型bool
は
true
かfalse
ゼロ値はfalse
==
による比較可能
###数値型
uint8 非負8-bit (0 to 255)
uint16 非負16-bit (0 to 65535)
uint32 非負32-bit (0 to 4294967295)
uint64 非負64-bit (0 to 18446744073709551615)
int8 8-bit (-128 to 127)
int16 16-bit (-32768 to 32767)
int32 32-bit (-2147483648 to 2147483647)
int64 64-bit (-9223372036854775808 to 9223372036854775807)
float32 IEEE-754 32-bit 浮動小数点
float64 IEEE-754 64-bit 浮動小数点
complex64 float32 複素数
complex128 float64 複素数
byte uint8のエイリアス
rune int32のエイリアス
uint 32-bit or 64-bit
int uintと同じ大きさ
uintptr ポインタを格納できる大きさ
ゼロ値は0
==
による比較 <
などによる順序比較可能
###文字列型
文字列の長さlen(文字列)
はバイト列の長さ
文字列は変更できない
文字列[添字]
でバイト列を参照する
&文字列[添字]
は不可
文字列[添字] = 文字
は不可
文字列[low : high]
は部分文字列を返す
ゼロ値は""
nilにならない
==
による比較が可能 <
などによる順序比較可能
byte列による辞書順で比較される
###配列型
配列[要素数]型T
は,型Tを要素数個格納できる型
要素数は静的に決定
[1][2][3]int
は[1]([2]([3]int))
make([要素数]型)
ゼロ初期化された配列
len(配列), cap(配列)
は要素数
[要素数]型{要素0, 要素1, …}
配列の合成リテラル
[...]型{要素0, 要素1, …}
要素数は...
とすると要素数となる
指定された要素数に対して要素が足りなければ要素はゼロ値となる
配列[添字]
により要素が得られる
配列[low : high]
によりスライスが得られる
得られたスライスは元の配列と要素を共有している
スライスを書き換えると配列も書き換わる
ゼロ値はそれぞれの要素がゼロ値となる
==
による比較が可能 個別の要素を比較する
###スライス型
スライス[]型T
は,型Tを格納する列の型
要素数が動的に決定
len(スライス)
は要素数
cap(スライス)
で予備を含めたスライスの大きさ=キャパシティーを得られる
make(スライス型, 長さ, キャパシティー)
キャパシティーを与えてゼロ初期化されたスライス
new([キャパシティー]スライス型)[0:長さ]
は上と等価
[]型{要素0, 要素1, …}
スライスの合成リテラル. キャパシティーは指定できない.
スライス[low : high]
によりスライスが得られる
得られたスライスはもとのスライスと要素を共有している
スライスを書き換えるともとのスライスも書き換わる
ゼロ値はnil
スライス型のnilは要素数0のスライスのように振る舞う
==
による比較ができない
###構造体
struct {複数のフィールド}は構造体型 変数0, 変数1, … 型
は名前付きフィールド (x int
, x, y int
)
型
だけ書くと埋め込みフィールドとなり, フィールド名は型と同じ
_ 型
はパディング
型{キー: 値…}
合成リテラル
キーを省略した場合,structの順番となる
値が足りないときはゼロ値となる
構造体Sに型Tを埋め込むと,型Tのフィールドとメソッドは構造体Sでも参照できる
type T struct {
X int
}
type S struct {
T // Tを埋め込む
}
func main() {
s := S{T{1}}
// s.X は S.T.X と同じ
fmt.Printf("%#+v: %v === %v", s, s.X, s.T.X)
// main.S{T:main.T{X:1}}: 1 === 1
}
フィールドは文字列のタグを持つ
タグが未指定の場合,空文字列のタグを持つ
リフレクションで参照できる
struct {
microsec uint64 `protobuf:"1"`
serverIP6 uint64 `protobuf:"2"`
}
ゼロ値はそれぞれのフィールドをゼロ値で初期化する
==
による比較可能 個別のフィールドを比較する
###ポインタ型
*T
はT
のポインタ型
&値
によりポインタが得られる
*ポインタ
により値を参照する
ゼロ値はnil
nilを参照すると実行時パニック
==
による比較可能
###関数型
func(引数) 返り値
は関数型
ゼロ値はnil
nilを呼び出すと実行時パニック
==
による比較不可能
###インターフェース型
interface{複数のシグネチャ}
はインターフェース型
シグネチャは メソッド名(引数)返り値
インターフェースIのすべてのシグネチャが型Tのメソッドの時, 型TはインターフェースIを実装していると言う
interface{}
は要求するメソッドが無いので, 全ての型が実装している
インターフェースは他のインターフェースを埋め込める
埋め込まれたインターフェースのシグネチャを取り込む
ReadWriter
はRead
とWrite
とClose
を持つ
type Reader interface {
Read(p []byte) (n int, err error)
Close() error
}
type Writer interface {
Write(p []byte) (n int, err error)
Close() error
type ReadWriter interface {
Reader
Writer
}
ゼロ値はnil
==
による比較可能 元の型として比較する
###マップ型
map[キー型]値型
はマップ型
make(map[キー型]値型, キャパシティー)
でキャパシティー付きのマップが作られる
map[キー型]値型{キー0: 値0, キー1: 値1, …}
len(マップ)
は要素数
マップ[キー]
は値とその存在を返す
-
キーが存在するとき,その値と
true
-
存在しないとき,ゼロ値と
false
v, ok = m[0]
ゼロ値はnil
nilはキーが存在しないマップとして振る舞う
==
による比較不可能
###チャンネル型
スレッドセーフなキュー
chan 型T
は 型Tを送受信するチャンネル型
chan <- 型T
は 型Tを送信するチャンネル型
<- chan 型T
は 型Tを受信するチャンネル型
make(chan 型T, キャパシティー)
はチャンネルを作る唯一の方法
キャパシティーはチャンネルのキューの大きさを示す
len(チャンネル)
はキュー内の要素数
cap(チャンネル)
はキューの大きさ
バッファーに要素があるとき, 受信は成功する
バッファーに要素がないとき, 受信は送信されるまでブロックする
バッファーが足りているとき, 送信は成功する
バッファーの要素がいっぱいのとき, 送信は受信されるまでブロックする
ゼロ値はnil
チャンネル型のnilは何も送受信されない
close(チャンネル)
によりチャンネルをクローズできる
==
による比較可能 同じmake()によって生み出されたか判定する
##型と値の性質
###型の同一性
- 異なるパッケージの非公開名前は区別される
- シグネチャの引数や返り値の名前は無視される
- キャパシティーは無視される
- エイリアスは同一の型となる
###代入可能
値xが型Tに代入可能である とは 次のいずれかを満たすことである:
- xの型VがTと同一である
- xの型VとTが同一の基底型を持ち, VとTの少なくともどちらかがDefined型ではない
- Tがインターフェース型であり, xがTを実装している
- x が送受信チャンネルでTがチャンネル型であり, VとTが同一の要素型をもち, VとTの少なくともどちらかがDefined型ではない
- xがnilであり,Tがポインタ,関数,スライス,マップ,チャンネル,インターフェースである
- xが定数であり,Tの値として表現可能
Defined型は, type 型名 型
で定義された型名の型のこと
type T1 T
, type T2 T
のとき,
Tの値はT1, T2に代入できるが, T1の値をT2に代入することはできない
###表現可能
定数xが型Tの値として表現可能であるとは,
要するに,定数がその型として扱えるということ
##ブロック
ブロックは文のリスト {文; 文; …}
暗黙的にブロックが生成される
- すべてのGoのソースコード全体=宇宙ブロック
- それぞれのパッケージのソースコード全体
- ファイル全体
-
if
,for
,switch
-
switch
,select
のブランチ
ブロックによってスコープが規定される
##宣言とスコープ
宣言は, 定数, 型, 変数の3種類
トップレベル宣言は, 宣言に加えて関数宣言とメソッド宣言の5種類
boolなどの事前宣言識別子は宇宙ブロックのスコープに属する
トップレベルの宣言はパッケージのスコープに属する
インポートしたパッケージはファイルのスコープに属する
他の名前は最も内側のブロックのスコープに属する
###ラベルのスコープ
定義されたラベルは用いる必要がある
ラベルは関数のブロックのスコープに属する. ラベル以外の識別子とは衝突しない
###ブランク識別子
_
はブランク識別子として特別な意味を持つ
###事前宣言識別子
Types:
bool byte complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
Constants:
true false iota
Zero value:
nil
Functions:
append cap close complex copy delete imag len
make new panic print println real recover
###エクスポートされる識別子
識別子の初めの文字がUnicodeの大文字クラス("Lu")であり,
パッケージブロックで宣言された名前である時
その識別子はエクスポートされる
###識別子の唯一性
同じスコープに同じ識別子は持てない
###定数定義
const 定数名 = 定義
により定数を定義できる
const 定数名 型 = 定義
により型を指定できる
iota
はconst()
の中で宣言ごとに0から1ずつ増える特別な値である.
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Partyday
numberOfDays // this constant is not exported
)
###Iota
1つの宣言の中ではiota
は同じ値となる
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0)
bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1)
_, _ // (iota == 2, unused)
bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3)
)
###型宣言
エイリアス型宣言
type エイリアス名 = 型
エイリアスは元の型と同一の型である
型宣言
type 型名N 型T
基底型をTとして新しい型を型名Nとして作る.
型名NはDefined型となる.
すなわち,type TimeZone int
はintと異なる振る舞いをする
また,Defined型はメソッドを持つことができる.
type TimeZone int
const (
EST TimeZone = -(5 + iota)
CST
MST
PST
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}
###変数宣言
var 変数名 型 = 値
で変数宣言
型と値は省略可能
参照されない変数はエラーとなる
_
により値を捨てることができる
var _, found = entries[name]
###短縮変数宣言
変数名 := 値
は var 変数名 = 値
の省略としてほとんど振る舞う
ただしvar
と異なり, 一部の変数への代入が可能
少なくとも1つは新しい変数を定義する必要がある
###関数定義
func 識別子 シグネチャ ブロック
により関数が定義される
返り値を返すならばブロックの最後のreturnを省略できない
ただし, if-elseと条件のないforのあるときは省略できることがある(see 終端文)
関数のブロックを省略した場合,アセンブリルーチンなどでGo以外の外部から定義が与えられることを想定される
###メソッド宣言
func (レシーバ変数 レシーバ型) 識別子 シグネチャ
によりメソッドが定義される
レシーバ型(*T, T)はTがDefined型である必要がある
メソッドの型はfunc (レシーバ型, メソッドの型...) メソッドの返り値
##式
###被演算子
被演算子はすべてのリテラルと識別子と修飾識別子と(式)
である
###修飾識別子
識別子にパッケージ名をつけることで別のパッケージの識別子を参照できる
パッケージ名.識別子
###合成リテラル
チャンネル以外の型には{}
によるリテラルがある
合成リテラルの例はそれぞれの型の節に移動した
複数の型が合成された型のとき, 内側の型名を省略できる
次の2つは同じ:
map[string]Point{"orig": {0, 0}}
map[string]Point{"orig": Point{0, 0}}
###関数リテラル
func シグネチャ 関数本体
は関数であり,クロージャを作る
外側の変数を参照するための環境を持つ
()
で呼び出すことができる
x.f
はxのフィールドかメソッドを返す
xが埋め込みフィールドを持つ場合, 幅優先で再帰的に探索する
- *xの型(T, T)でTがポインタでもインターフェースでもない
- 探索時に最も浅いところのfを返す
- 同じ深さに同じfがあるならば不正
-
xの型がインターフェースI
- xの動的な実際の型のfを返す.
- fがインターフェースIのメソッドでないならば不正
-
xがポインタ型 (例外)
- xの実体である
(*x).f
が不正でないならx.fはP(*x).f
の短縮となる
- xの実体である
-
xがポインタ型でnil
- 実行時パニック
-
xがインターフェースでnil
- x.fを評価もしくは呼び出した時に実行時パニック
###メソッド式
型.メソッド
や(*型).メソッド
により関数が得られる
###メソッド値
値.メソッド
により関数が得られる
###添字式
値a[添字i]
-
値aがポインタのとき,
(*値a)[添字i]
と等価 - マップ,配列,スライス,文字列のとき それぞれの型のところで示した
###スライス式
値a[low:higth]
は部分文字列やスライスを返す
値aがポインタのとき,(*値a)[low:high]
と等価
low
を省略すると0,high
を省略するとlen(値a)
となる
###型アサーション
値x.(型T)
により実行時に型変換ができる
- 型Tがインターフェースのとき,xはTを実装している必要がある
- 型Tがインターフェースでないとき,Tはxの型を実装している必要がある
そうでなければ実行時パニックを起こす
ただしv, ok := x.(T)
の形で呼び出した場合は, 実行時パニックを起こさない
かわりにvがゼロ値, okがfalseとなる
###呼び出し
関数は複数の値を返すことができる
返した複数の値は次のどれかを行う必要がある
- 分割代入する:
x, y := f()
- returnする:
return f()
- 合成する:
g(f())
###多引数関数 ...引数
who ...string)
関数の最後の引数を...型
にできる.
渡した引数がスライスとして渡される
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
スライス...
で...引数
に渡すことができる
s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)
###演算子
###数値演算
-
数値
+
-
*
/
%
-
ビット
|
^
<<
>>
&
&^
-
単項演算子
+
-
^
&^
はbit clear(AND NOT)
存在理由→stack overflow
オーバーフローしてもパニックではなくwrap-aroundする
x < x+1
が常にtrue
とは限らない
小数の演算は積和演算(FMA)などの丸めで結果が異なることがある
文字列は +
で結合できる
ただし, 多くの文字列を結合するならばstrings.Builder
を用いるべき
###比較演算
-
比較
==
!=
-
順序
<
<=
>
>=
比較する2値は互いに代入可能である必要がある
スライス,マップ,関数は比較できない
- 真偽値,整数,小数 比較可能かつ順序付け可能
- 複素数 real→imagの辞書順比較で順序付けされる
- 文字列 bit列での辞書順比較で順序付けされる
- ポインタ 比較可能. 大きさゼロの要素のポインタ値は異なることがある
- チャンネル makeで作られた同じチャンネルであるか比較する
- インターフェース 同じ型で同じ値か比較する
- 構造体 すべてのフィールドの値が同じか比較する
- 配列 すべての要素が同じか比較する
###論理演算子
-
短絡演算
||
&&
-
単項演算子
!
###アドレス演算
-
参照
&x
-
参照先の値を得る
*x
###受信演算
-
受信
<-ch
受信する.
バッファーが無いときは送信があるまでブロックする
x, ok = <-ch
のとき, 受信に成功したかクローズしたかを返す
受信に成功すればok=trueとなる
###コンバージョン
型T(値x)
コンパイル時に検査される型変換
xが定数の時 値xが型Tとして表現可能でなければ不正
xが定数でない時 次のどれかを満たす
- xがTに代入可能
- 構造体のタグを無視して, xの型がTの基底型と同一
- 構造体のタグを無視して, xの型とTのポインター型がDefined型ではなく,それらの基底型が同一
- xが整数か小数で,Tが整数型か小数型
- xが複素数で,Tが複素数型
- xが整数か[]byteか[]runeで,Tが文字列
- xが文字列で, Tが[]byteか[]rune
すなわち,次のキャストが可能
- 構造体のタグを無視するキャスト
- 数値のキャスト
- 文字列とスライスのキャスト
###定数式
定数の演算は定数式になる
###評価順
関数の引数の評価は左から右に行われる
##文
###終端文
return以外でも終了文がある
-
return
goto
panic
-
if-else
for
switch
select
(条件あり)
###空文
空文は何もしない
###ラベル付き文
ラベル: 文
###式文
式は文である
###送信文
チャンネルに値を送信する
ch <- 3
x++
x--
###代入
x = 1
x += 1
a, b = b, a
###If文
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
###Switch文
式Switch文
switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}
switch { // switch trueと等価
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}
型Switch文
switch 変数 := 変数.(type)
順番に型アサーションを試し,成功したブランチを実行する
switch i := x.(type) {
case nil:
print("x is nil")
case int:
print(i+1)
}
###For文
1条件For
for a < b {
a *= 2
}
for { // for trueと等価
if a < b {
break
}
}
### 3条件For
for i := 0; i < 10; i++ {
f(i)
}
range For
for i, v := range a {
print(i, v)
}
- aが配列,スライスの時 iは添字, vは要素
- aが文字列の時 iはUTF-8での添字,vはRune
- aがマップの時 iはキー,vは要素 順序不定 ループ中の要素追加は不定
- aがチャンネルの時 1要素 チャンネルがCloseするまで受信ループ
###Go文
最後の関数適用がゴルーチンとして並列に実行される
go Server()
go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
###Select文
実行できる受信/送信を1つ当確率にランダムに実行する.
すべての受信/送信がブロックした場合,defaultがあればdefaultを実行する
select {
case <- c1:
case x := <- c2:
default: // ブロックしない
}
// 0,1をランダムに送信し続ける
for {
select {
case c <- 0:
case c <- 1:
}
}
###Return文
名前付き返り値を用いることができる
func complexF3() (re float64, im float64) {
re = 7.0
im = 4.0
return
}
###Break文
一番内側のfor
switch
select
を抜ける
もしくは指定したラベルまで抜ける
###Continue文
for
に戻る
もしくは指定したラベルのfor
に戻る
###Goto文
指定したラベルに処理を移す
###Fallthrough文
switch
内で次のブランチも実行する
###Defer文
最後の関数呼び出しを,現在の関数から抜けるreturn
やpanic
のタイミングで実行する
defer
の実行は文の順番と逆に行われる
次の時実行時パニック
- 閉じたチャンネルを閉じる
- 閉じたチャンネルに送信する
- nilを閉じる
それぞれの型の説明で説明済み
###確保 new
new(T)
は型のゼロ値を返す
ほとんどの場合T{}
と等価
###スライス,マップ,チャンネルの生成
make(型, 要素数 キャパシティ)
を指定できる
appendでスライスの末尾に複数要素を追加できる
appendの第1引数は使い回され変更を受けることがある
b := append(a, 1, 2)
b := append(a, c...)
copyはsrcの要素をdstに代入する
copy(dst, src []T) int
###マップからキーを削除 delete
キーが存在しない場合は何もしない
delete(m, k)
complex(realPart, imaginaryPart floatT) complexT
real(complexT) floatT
imag(complexT) floatT
panicは直ちにすべての関数を抜けようとする
func panic(interface{})
func recover() interface{}
deferでrecover()を呼ぶとパニックの送出が止まる
パニックしたときの引数が得られる
func protect(g func()) {
defer func() {
log.Println("done") // Println executes normally even if there is a panic
if x := recover(); x != nil {
log.Printf("run time panic: %v", x)
}
}()
log.Println("start")
g()
}
###ブートストラッピング print/println
デバッグ出力, 標準エラー出力に出ることが多い
print("Hello")
println("World")
##パッケージ
Goのビルド単位
###ソースファイル
Goのソースファイルは
package パッケージ名
複数のインポート宣言
から始まる
###インポート宣言
パッケージをインポートするときは,
パッケージ名に別名をつけることや
現在のパッケージと名前空間を共有することができる
パッケージ名は実装依存
import "lib/math" → math.Sin
import m "lib/math" → m.Sin
import . "lib/math" → Sin
###ゼロ値
確保された変数は初期値がない場合,ゼロ値になる.
false
0
""
nil
のいずれか
###パッケージの初期化
パッケージグローバルの変数は依存の解決されたものから上から順番に初期化される.
パッケージのinit()
が呼ばれる.
init()
は何回でも定義できる.
init()
はプログラムの他の場所から参照できない.
インポートされたパッケージが先に初期化される.
複数回インポートされるパッケージは1回だけ初期化される.
パッケージ間の循環参照は起こせない.
###プログラムの実行
mainパッケージのmain()
が実行される,
##エラー error
error
型はインターフェースである.
type error interface {
Error() string
}
nilはエラーのないことを示す.
panic
関数はerror型を受け取り,実行時パニックを起こす
##システム関係
###unsafeパッケージ
package unsafe
type ArbitraryType int // shorthand for an arbitrary Go type; it is not a real type
type Pointer *ArbitraryType
func Alignof(variable ArbitraryType) uintptr
func Offsetof(selector ArbitraryType) uintptr
func Sizeof(variable ArbitraryType) uintptr
Offsetofは要素のオフセットを返す
uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))
Alignof(x)はアライメントを返す
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
数値型は固定サイズである.
type size in bytes
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16
structのアライメントは要の最大のアライメントと等しい.
arrayのアライメントは要素のアライメントと等しい
ゼロ要素のstructやarrayは0より大きい大きさを持つことがある.
ゼロ要素の異なる変数が同じメモリに配置されることがある.