パッケージ、変数、関数

The Go Authors

目次

1. パッケージ

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))
}

2. インポート

このコードでは、括弧でパッケージのインポートをグループ化し、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))
}

3. 名前のエクスポート

Goでは、最初の文字が大文字で始まる名前は、外部のパッケージから参照できるエクスポート(公開)された名前( exported name )です。 例えば、 Pimath パッケージでエクスポートされています。

小文字ではじまる pihoge などはエクスポートされていない名前です。

パッケージをインポートすると、そのパッケージがエクスポートしている名前を参照することができます。 エクスポートされていない名前(小文字ではじまる名前)は、外部のパッケージからアクセスすることはできません。

コードを実行し、エラーを確認してみましょう。

エラーを修正するために、 math.pimath.Pi に書き換え、もう一度実行してみてください。

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi)
}

4. 関数

関数は、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))
}

5. 関数(続)

関数の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))
}

6. 複数戻り値

関数は複数の戻り値を返すことができます。

この 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)
}

7. 名前付き戻り値

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))
}

8. 変数

var ステートメントは変数( variable )を宣言します。 関数の引数リストと同様に、複数の変数の最後に型を書くことで、変数のリストを宣言できます。

var ステートメントはパッケージ、または、関数で利用できます。例のコードで示します。

package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}

9. 初期化子

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)
}

10. 変数宣言の短縮形

関数の中では、 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)
}

11. 基本型

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)
}

12. ゼロ値

変数に初期値を与えずに宣言すると、ゼロ値( zero value )が与えられます。

ゼロ値は型によって以下のように与えられます:

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)
}

13. 型変換

型変換

変数 v 、型 T があった場合、 T(v) は、変数 vT 型へ変換します。

いくつかの変換を見てみましょう:

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

よりシンプルに記述できます:

i := 42
f := float64(i)
u := uint(f)

C言語とは異なり、Goでの型変換は明示的な変換が必要です。 例のコードで、 float64uint の変換を削除し、何が起きるのか確認しましょう。

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)
}

14. 型推論

明示的な型を指定せずに変数を宣言する場合( :=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)
}

15. 定数

定数( 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)
}

16. 数値の定数

数値の定数は、高精度な ( 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))
}

17. Congratulations!

この章はこれで終わりです。

章のリストから学びたいところを見ても良いですし、 > をクリックして次の章へ進みましょう。