Go (プログラミング言語)
![]() Goのロゴ | |
パラダイム |
構造化プログラミング、手続き型プログラミング、命令型プログラミング、並行計算、オブジェクト指向プログラミング、関数型プログラミング ![]() |
---|---|
登場時期 | 2009年11月10日 |
設計者 | Robert Griesemer、ロブ・パイク、ケン・トンプソン |
開発者 | |
最新リリース |
1.22.4[1] ![]() |
型付け | 強い、静的、型推論、構造的[2][3] |
主な処理系 | gc、gccgo |
影響を受けた言語 |
C言語、Oberon-2、Limbo、Active Oberon、Communicating Sequential Processes、Pascal、Oberon-2、Smalltalk、Newsqueak、Modula-2、Alef、APL、BCPL、Modula、Occam ![]() |
影響を与えた言語 | Crystal |
プラットフォーム |
DragonFly BSD、FreeBSD、Linux、macOS、NetBSD、OpenBSD、Plan 9 from Bell Labs、Solaris、Microsoft Windows、iOS、Android、AIX、illumos ![]() |
ライセンス |
BSDライセンス ![]() |
ウェブサイト | |
拡張子 |
go ![]() |
名称
編集歴史
編集コード例
編集Hello world
編集次のコードはGoで書いたHello worldプログラムである。
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
}
並行性の例
編集次のサンプルプログラムは、Goの並行性機能をデモンストレーションする非同期プログラムの実装である。2つの"goルーチン"(軽量スレッド)を立ち上げている。一方はユーザーがテキストを入力するのを待機し、他方はタイムアウトを実現する。select文が2つのgoルーチンがメインルーチンにメッセージを送信するのを待機し、最初に到達したメッセージに対して動作を実行する(コード例はDavid Chisnallの本のコードを一部修正している)[28]:152。
package main
import (
"fmt"
"time"
)
func readword(ch chan string) {
fmt.Println("Type a word, then hit Enter.")
var word string
fmt.Scanf("%s", &word)
ch <- word
}
func timeout(t chan bool) {
time.Sleep(5 * time.Second)
t <- true
}
func main() {
t := make(chan bool)
go timeout(t)
ch := make(chan string)
go readword(ch)
select {
case word := <-ch:
fmt.Println("Received", word)
case <-t:
fmt.Println("Timeout.")
}
}
言語機能の特徴
編集文法
編集構造体
編集Goにはユーザー定義の複合型を記述することのできる構造体の機能があり、下記のように記述する。
package main import "fmt" // 新しい構造体型の定義。各フィールドの識別子とその型名を指定。 type Person struct { name string // 名前。 age int // 年齢。 } // メソッドの定義。 func (m *Person) PrintName() { fmt.Printf("Name = %s\n", m.name) //fmt.Printf("Name (%T) = %#v\n", m.name, m.name) } func (m *Person) PrintAge() { fmt.Printf("Age = %d\n", m.age) //fmt.Printf("Age (%T) = %#v\n", m.age, m.age) } func main() { var person Person person.name = "John Smith" person.age = 24 // 以下のように書くこともできる。 //person := Person{ "John Smith", 24 } person.PrintName() person.PrintAge() // 以下のように書式指定すると、型名とリテラル表現を出力できる。 fmt.Printf("person (%T) = %#v\n", person, person) }
name
およびage
というフィールドを持つPers
on
構造体の型を定義し、さらにその構造体に対応するPrintNa
me()
およびPrintAge()
というメソッドを定義している。GoにはJavaのような言語が持つクラスやオブジェクトのような概念は無いが、実質的には構造体はそれらに近い役割を提供する。
Goでは、関数に(m *Person)
のようなレシーバーの宣言を追加してメソッドを定義する。レシーバーの宣言は (変数名 型名)
と記述する。レシーバー内の変数名は自由に指定が可能であり、受け取り方は値渡し、ポインター渡しの2種類から指定できる。
型とメソッドが切り離されており、型は一切メソッドに依存しない。メソッドと型は、メソッドの追加対象となる型名をレシーバーの型名に指定することで関連付けるようになっている。メソッドは型から切り離されているため型本体を変更する事なくメソッドを追加することが可能であり、同一パッケージ内限定ではあるが、開放された型を実現している。
Goには型自身を初期化したり終了したりする機能が存在しない。つまりJavaの静的イニシャライザやC#の静的コンストラクタに相当する機能がない。初期化は型に所属しない関数や、他の型のメソッドで行うようになっている。
新しい型の定義
編集Goではtype構文を利用して既存の型から新しい型を定義できる。
次の例では、int
型を元に MathInt
という新しい型を定義している。
type MathInt int
int
型と別の型を定義している点が大きく異なる。
新しく定義した型であれば、元の型が構造体型でなくともメソッドを追加することができる。例えばint
型やマップ型といった事前定義済み型 (組み込み型) に対してもメソッドを追加することが可能である。
事前定義済み型から新しい型を定義した場合、例えば下記のような記述が可能となる。
package main
import (
"fmt"
"math"
)
type MathInt int
func (x MathInt) Abs() float64 {
return math.Abs(float64(x))
}
func main() {
var x MathInt = -10
fmt.Printf("%d\n", x) // -> -10
fmt.Printf("%f\n", x.Abs()) // -> 10.000000
fmt.Printf("%T\n", x) // -> main.MathInt
}
Go 1.9ではtypeキーワードを利用した型エイリアス (type alias) 構文が別途追加された[30]。こちらはC/C++のtypedefやC#のusingエイリアスディレクティブと類似の機能である。
package main
import (
"fmt"
"math"
)
type MyInt = int
func main() {
var x MyInt = -10
fmt.Printf("%d\n", x) // -> -10
fmt.Printf("%f\n", math.Abs(float64(x))) // -> 10.000000
fmt.Printf("%T\n", x) // -> int
}
匿名フィールド
編集Goには継承が意図的に実装されていない。しかし匿名フィールドという機能を用いることで、ある構造体と同じフィールド、メソッドを持つ構造体を容易に作成することができる。
type Base int
func (_ *Base) Function() {
}
type Derived struct {
Base
}
// 呼び出し例
var derived Derived
derived.Function()
このようにして作られた構造体から匿名フィールドで用いられた元となる構造体の型に暗黙的にキャストするような機能は存在していない。
interface
編集type Container interface {
Begin() Iterator
End() Iterator
}
Goのinterfaceは、MLのsignatureや、かつてg++に存在したsignatureというC++拡張と全く同じ機能である。
defer
編集defer
文という例外安全な強制実行のしくみを採用している。
defer
文は、defer
キーワードに続けて、関数呼び出しまたはメソッド呼び出しを記述することで関数終了時に[注釈1]指定した処理の呼び出しを実行する。
ファイルのオープンとクローズなど、組になる作業で両方行われる必要があるものに多く使われる。
defer
は下記の様に記述する。
defer 関数呼び出しまたはメソッド呼び出し
defer
はブロックを持たず入れ子が深くなるようなことはない。ただし、関数以外のブロックを無視する点に注意が必要である。例えばループ中でdefer
を使用した場合、ループ内では指定した関数が呼ばれず関数終了時にdefer
で指定した全ての関数呼び出しが行われる。
defer
には、関数呼び出しまたはメソッド呼び出ししか記述できず[注釈2]、式や文を直接記述することはできないが、下記のように無名関数の即時実行を利用して、任意の式や文の実行も可能である。
defer func() {
message := "done"
fmt.Println(message)
}()
例外処理
編集try-catch
のような事もできるが推奨されない。例外機能は、主に0除算など起きてはならないことに使われ普通は強制終了するが、リカバーによって強制終了しないようにする事も可能である。Goでは、事前に例外が起きないよう確認する事や、成功かどうかのBool値を返す事のような、例外を起こさない方法が好まれる。
ダウンキャスト
編集Goはインターフェース型の値から、基底型の値(インターフェース型に変換される前の型の値)を動的に安全に得るダウンキャストの仕組みとして「型アサーション」と呼ばれる機能を備えている。
// Value の返値はどんな型でも構わない
var i interface{} = Value()
/*
i の基底型を string と仮定し、
実際にそうであれば s には変換結果が、 ok には true がセットされ、
そうでなければ s にはstring型の初期値(ゼロ値)が、 ok には false がセットされる。
以下の様に2つ目の返値を無視すると、i の基底型が string でなければ暗黙的にランタイムパニックとなる
s := i.(string)
*/
if s, ok := i.(string); ok {
fmt.Println ("文字列: ", s)
} else {
var kind string
// 型switch
switch i.(type) {
case int:
kind = "数値"
default:
kind = "その他"
}
fmt.Printf ("%s: %v\n", kind, i)
}
標準パッケージのreflectを使うことで[31]、対象の値型やその値などの詳細を得ることができる。
名前とモジュールの管理
編集Goには名前とモジュールを管理するために、パッケージという仕組みを持っている。
基本的なパッケージの使用例を下記に示す。
package main // 現在のソースファイルが所属するパッケージ名の指定
// 本記事の例では省略されている事が多いが本来は必須である
import _ "./sub/a" // (1)ソースファイル中から名前が使用されないパッケージの取り込み
import . "./sub/b" // (2)パッケージ名を省略して、パッケージ内の名前を現在のソースファイルに全て取り込む
import alias_c "./sub/c" // (3)パッケージ名に別名を付けてパッケージ名を現在のソースファイルに取り込む
import "./sub/d" // (4)パッケージ名に末端のパッケージ名と同じ名前を付けて現在のソースファイルに取り込む
func main() {
Function() // (2)のパッケージに所属するFunctionの呼び出し
alias_c.Function() // (3)のパッケージに所属するFunctionの呼び出し
d.Function() // (4)のパッケージに所属するFunctionの呼び出し
}
import
文が存在するが、その構成要素は、別名の指定とGoのソースを格納したフォルダーの指定︵またはパッケージバイナリー︶という非常に単純なものである。Goでは名前管理とモジュールの取り込み指定を一つの構文にまとめる事で、他の言語では煩わしいモジュールの結合を簡潔なものとしている。
Goの名前管理の特筆する点として名前解決の方法として階層型の名前空間ではなく別名の仕組︵のみ︶を採用している点が挙げられる。名前解決をするために長い名前[注釈3]を記述する煩わしさはない。
更にGoにはモジュール管理の点でも特筆すべき点がある。Goはソースファイル中に一つ初期化関数︵init
︶を定義する事で、初期化関数により実行時に広域変数を初期化できるという機能を持っている。この初期化関数が呼ばれるソースファイルは、main
関数の定義されたソースファイルから連鎖的にimport
されたパッケージに含まれるソースファイルだけである。この特性により使う予定もないのに初期化コードが実行されるおそれはない。また、パッケージが初めて参照されるまで初期化が遅延されてしまうという事もない。
アクセス指定子
編集提供しない機能
編集処理系
編集脚注
編集注釈
編集出典
編集関連項目
編集解説書籍など
編集go instal
l golang.org/x/website/tour@late
st
を実行することで必要最小限のファイルがダウンロードされる。その後、tourを実行することで、オフラインでGoの文法を学ぶことができる。