Goのプログラムは、パッケージ( package )で構成されます。
プログラムは main
パッケージから開始されます。
このプログラムでは "fmt"
と "math/rand"
パッケージをインポート( import )しています。
規約で、パッケージ名はインポートパスの最後の要素と同じ名前になります。
例えば、インポートパスが "math/rand"
のパッケージは、 package rand
ステートメントで始まるファイル群で構成します。
(もしURLを含むインポートパスが "golang.org/x/net/websocket" だった場合は、 package websocket
になります)
package main import ( "fmt" "math/rand" ) func main() { fmt.Println("My favorite number is", rand.Intn(10)) }
このコードでは、括弧でパッケージのインポートをグループ化し、factoredインポートステートメント( factored import statement )としています。
もちろん、複数のインポートステートメントで書くこともできます:
import "fmt" import "math"
ですが、先に示したfactoredインポートステートメントの方がより良いスタイルです。
訳注: ここの factored の意味は、「要素化、グループ化、整理済み」ということです。良い日本語募集中。
package main import ( "fmt" "math" ) func main() { fmt.Printf("Now you have %g problems.", math.Sqrt(7)) }
Goでは、最初の文字が大文字で始まる名前は、外部のパッケージから参照できるエクスポート(公開)された名前( exported name )です。
例えば、 Pi
は math
パッケージでエクスポートされています。
小文字ではじまる pi
や hoge
などはエクスポートされていない名前です。
パッケージをインポートすると、そのパッケージがエクスポートしている名前を参照することができます。 エクスポートされていない名前(小文字ではじまる名前)は、外部のパッケージからアクセスすることはできません。
コードを実行し、エラーを確認してみましょう。
エラーを修正するために、 math.pi
を math.Pi
に書き換え、もう一度実行してみてください。
package main import ( "fmt" "math" ) func main() { fmt.Println(math.pi) }
関数は、0個以上の引数を取ることができます。
この例では、 add
関数は、 int
型の2つのパラメータを取ります。
変数名の 後ろ に型名を書くことに注意してください。
(型をなぜこのように宣言するのか、についての詳細な情報は、 記事「Go's declaration syntax」 を参照してください。)
package main import "fmt" func add(x int, y int) int { return x + y } func main() { fmt.Println(add(42, 13)) }
関数の2つ以上の引数が同じ型である場合には、最後の型を残して省略して記述できます。
この例では、
x int, y int
を
x, y int
へ省略できます。
package main import "fmt" func add(x, y int) int { return x + y } func main() { fmt.Println(add(42, 13)) }
関数は複数の戻り値を返すことができます。
この swap
関数は2つの string を返します。
とても簡単に交換できますね!
package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) }
Goでの戻り値となる変数に名前をつける( named return value )ことができます。戻り値に名前をつけると、関数の最初で定義した変数名として扱われます。
この戻り値の名前は、戻り値の意味を示す名前とすることで、関数のドキュメントとして表現するようにしましょう。
名前をつけた戻り値の変数を使うと、 return
ステートメントに何も書かずに戻すことができます。これを "naked" return と呼びます。
例のコードのように、naked returnステートメントは、短い関数でのみ利用すべきです。長い関数で使うと読みやすさ( readability )に悪影響があります。
package main import "fmt" func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return } func main() { fmt.Println(split(17)) }
var
ステートメントは変数( variable )を宣言します。
関数の引数リストと同様に、複数の変数の最後に型を書くことで、変数のリストを宣言できます。
var
ステートメントはパッケージ、または、関数で利用できます。例のコードで示します。
package main import "fmt" var c, python, java bool func main() { var i int fmt.Println(i, c, python, java) }
var
宣言では、変数毎に初期化子( initializer )を与えることができます。
初期化子が与えられている場合、型を省略できます。その変数は初期化子が持つ型になります。
package main import "fmt" var i, j int = 1, 2 func main() { var c, python, java = true, false, "no!" fmt.Println(i, j, c, python, java) }
関数の中では、 var
宣言の代わりに、短い :=
の代入文を使い、暗黙的な型宣言ができます。
なお、関数の外では、キーワードではじまる宣言( var
, func
, など)が必要で、 :=
での暗黙的な宣言は利用できません。
package main import "fmt" func main() { var i, j int = 1, 2 k := 3 c, python, java := true, false, "no!" fmt.Println(i, j, k, c, python, java) }
Go言語の基本型(組み込み型)は次のとおりです:
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 の別名 rune // int32 の別名 // Unicode のコードポイントを表す float32 float64 complex64 complex128
(訳注:runeとは古代文字を表す言葉(runes)ですが、Goでは文字そのものを表すためにruneという言葉を使います。)
例では、いくつかの型の変数を示しています。また、変数宣言は、インポートステートメントと同様に、まとめて( factored )宣言可能です。
int
, uint
, uintptr
型は、32-bitのシステムでは32 bitで、64-bitのシステムでは64 bitです。
サイズ、符号なし( unsigned )整数の型を使うための特別な理由がない限り、整数の変数が必要な場合は int
を使うようにしましょう。
package main import ( "fmt" "math/cmplx" ) var ( ToBe bool = false MaxInt uint64 = 1<<64 - 1 z complex128 = cmplx.Sqrt(-5 + 12i) ) func main() { fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe) fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt) fmt.Printf("Type: %T Value: %v\n", z, z) }
変数に初期値を与えずに宣言すると、ゼロ値( zero value )が与えられます。
ゼロ値は型によって以下のように与えられます:
0
false
""
(空文字列( empty string ))package main import "fmt" func main() { var i int var f float64 var b bool var s string fmt.Printf("%v %v %v %q\n", i, f, b, s) }
型変換
変数 v
、型 T
があった場合、 T(v)
は、変数 v
を T
型へ変換します。
いくつかの変換を見てみましょう:
var i int = 42 var f float64 = float64(i) var u uint = uint(f)
よりシンプルに記述できます:
i := 42 f := float64(i) u := uint(f)
C言語とは異なり、Goでの型変換は明示的な変換が必要です。
例のコードで、 float64
や uint
の変換を削除し、何が起きるのか確認しましょう。
package main import ( "fmt" "math" ) func main() { var x, y int = 3, 4 var f float64 = math.Sqrt(float64(x*x + y*y)) var z uint = uint(f) fmt.Println(x, y, z) }
明示的な型を指定せずに変数を宣言する場合( :=
や var =
のいずれか)、変数の型は右側の変数から型推論されます。
右側の変数が型を持っている場合、左側の新しい変数は同じ型になります:
var i int j := i // j is an int
右側に型を指定しない数値である場合、左側の新しい変数は右側の定数の精度に基いて int
, float64
, complex128
の型になります:
i := 42 // int f := 3.142 // float64 g := 0.867 + 0.5i // complex128
例のコードにある変数 v
の初期値を変えて、型がどのように変化するかを見てみてください。
package main import "fmt" func main() { v := 42 // change me! fmt.Printf("v is of type %T\n", v) }
定数( constant )は、 const
キーワードを使って変数と同じように宣言します。
定数は、文字(character)、文字列(string)、boolean、数値(numeric)のみで使えます。
なお、定数は :=
を使って宣言できません。
package main import "fmt" const Pi = 3.14 func main() { const World = "世界" fmt.Println("Hello", World) fmt.Println("Happy", Pi, "Day") const Truth = true fmt.Println("Go rules?", Truth) }
数値の定数は、高精度な 値 ( values )です。
型のない定数は、その状況によって必要な型を取ることになります。
例で needInt(Big)
を出力してみてください。
( int
は64-bitの整数を保持できますが、それでは足りないことが時々あります。そういったときにconstを活用しましょう)
package main import "fmt" const ( // Create a huge number by shifting a 1 bit left 100 places. // In other words, the binary number that is 1 followed by 100 zeroes. Big = 1 << 100 // Shift it right again 99 places, so we end up with 1<<1, or 2. Small = Big >> 99 ) func needInt(x int) int { return x*10 + 1 } func needFloat(x float64) float64 { return x * 0.1 } func main() { fmt.Println(needInt(Small)) fmt.Println(needFloat(Small)) fmt.Println(needFloat(Big)) }
この章はこれで終わりです。