diff --git a/ja/01.1.md b/ja/01.1.md index 4f09c48f..0acdad0a 100644 --- a/ja/01.1.md +++ b/ja/01.1.md @@ -3,8 +3,8 @@ ## 3つのインストール方法 Goにはいくつものインストール方法があります。どれでも好きなのを選んでかまいません。ここでは3つのよくあるインストール方法をご紹介します: -- ソースコードのインストール:標準的なインストール方法です。Unix系システムをよく使うユーザ、特に開発者にとってはお馴染みの方法です。 -- 標準パッケージのインストール:Goは便利なインストールパッケージを用意しています。Windows, Linux, Macなどのシステムをサポートしています。初心者にはうってつけでしょう。システムのbit数に対応したインストールパッケージをダウンロードして、"Next"をたどるだけでインストールできます。 +- ソースコードのインストール:標準的なインストール方法です。Unix系システムをよく使うユーザ、特に開発者であれば、設定を好みに合わせて変更できます。 +- 標準パッケージのインストール:Goは便利なインストールパッケージを用意しています。Windows, Linux, Macなどのシステムをサポートしています。とりあえずさっとインストールするにはうってつけでしょう。システムのbit数に対応したインストールパッケージをダウンロードして、"Next"をたどるだけでインストールできます。 **おすすめ** - サードパーティツールによるインストール:現在便利なサードパーティパッケージも多くあります。たとえばUbuntuのapt-get、Macのhomebrewなどです。これらのシステムに慣れたユーザにはぴったりのインストール方法です。 最後に同じシステムの中で異なるバージョンのGoをインストールする場合は、[GVM](https://github.com/moovweb/gvm)が参考になります。どうすればよいか分からない場合一番うまくやれます。 @@ -18,25 +18,25 @@ Unixでは、gccなどのツールをインストールする必要がありま Windowsでは、MinGWをインストールする必要があります。その後MinGWでgccをインストールして、適切な環境変数を設定します。 -Goは[Mercurial][hg]を使ってバージョン管理を行っています、まずMercurialをインストールし、その後でダウンロードできます。もしMercurialがインストールされているのであれば、以下のコードを実行します: +直接オフィシャルサイトから[ソースコードをダウンロード](http://golang.org/dl/)できます。対応する`goVERSION.src.tar.gz`のファイルをダウンロードし、`$HOME`ディレクトリに解凍してから以下のコマンドを実行します。 -もしGoのインストールディレクトリが`$GO_INSTALL_DIR`だった場合 - - hg clone -u release https://code.google.com/p/go cd go/src ./all.bash all.bashを実行後"ALL TESTS PASSED"が表示されると、インストール成功です。 -上記はUnixスタイルのコマンドです、Windowsもインストール方法は似ており、all.batを実行するだけです。コンパイラはMinGWのgccを使います。 +上記はUnixスタイルのコマンドです、Windowsもインストール方法は似ており、`all.bat`を実行するだけです。コンパイラはMinGWのgccを使います。 -その後環境変数をいくつか設定します、 +もしMacまたはUnixユーザであればいくつかの環境変数を設定する必要があります。再起動しても有効にしたい場合は以下のコマンドを`.bashrc`や`.zsh`に書いておきます。 - export GOROOT=$HOME/go - export GOBIN=$GOROOT/bin - export PATH=$PATH:$GOBIN + export GOPATH=$HOME/gopath + export PATH=$PATH:$HOME/go/bin:$GOPATH/bin -下のような画像が現れると、インストール成功です。 +ファイルに書き込んだ場合は、`bash .bashrc`や`bash .zshrc`を実行してすぐに設定を有効にします。 + +Windowsシステムの場合は、環境変数を設定する必要があります。pathにgoが存在するディレクトリを追加し、gopath変数を設定します。 + +設定が終わり、コマンドプロンプトで`go`を入力すると、下図のような画面が表示されるはずです。 ![](images/1.1.mac.png?raw=true) @@ -44,13 +44,17 @@ all.bashを実行後"ALL TESTS PASSED"が表示されると、インストール GoのUsage情報が表示されれば、Goのインストールは成功です:もしこのコマンドが存在しない場合は、PATH環境変数のなかにGoのインストールディレクトリが含まれているか確認してください。 +> GOPATHについては以降の章で詳しくご説明します ## Go標準パッケージのインストール Goはさまざまなプラットホームでインストールパッケージを提供しています、これらのパッケージはデフォルトで以下のディレクトリにインストールします:/usr/local/go(Windows:c:\Go)。当然これらのインストール場所を変更することもできます、ただし変更後はあなたの環境変数を以下のように設定する必要があります: export GOROOT=$HOME/go - export PATH=$PATH:$GOROOT/bin + export GOPATH=$HOME/gopath + export PATH=$PATH:$GOROOT/bin:$GOPATH/bin + +これらのコマンドはMacやUnixユーザであれば`.bashrc`や`.zshrc`ファイルに入れておくべきでしょう。Windowsユーザであれば当然環境変数に入れておきます。 ### 自分の操作しているシステムが32bitか64bitか判断する方法 @@ -72,7 +76,7 @@ LinuxユーザはTerminalで`arch`(すなわち、`uname -a`)を実行するこ ### Mac インストール -[ダウンロードURL][downlink]にアクセスし、32bitシステムはgo1.0.3.darwin-386.pkgをダウンロードします。64bitシステムであればgo1.0.3.darwin-amd64.pkgをダウンロードします。ファイルをダブルクリックし、すべてデフォルトで「次へ」ボタンをクリックします。これでgoはあなたのシステムにインストールされました。デフォルトでPATHの中に適切な`~/go/bin`が追加されています。端末を開いて`go`と入力します。 +[ダウンロードURL][downlink]にアクセスし、32bitシステムはgo1.4.2.darwin-386-osx10.8.pkgをダウンロードします。64bitシステムであればgo1.4.2.darwin-amd64-osx10.8.pkgをダウンロードします。ファイルをダブルクリックし、すべてデフォルトで「次へ」ボタンをクリックします。これでgoはあなたのシステムにインストールされました。デフォルトでPATHの中に適切な`~/go/bin`が追加されています。端末を開いて`go`と入力します。 インストール成功の画像が表示されればインストール成功です。 @@ -80,11 +84,11 @@ LinuxユーザはTerminalで`arch`(すなわち、`uname -a`)を実行するこ ### Linux インストール -[ダウンロードURL][downlink]にアクセスし、32bitシステムであればgo1.0.3.linux-386.tar.gzを、64bitシステムであればgo1.0.3.linux-amd64.tar.gzをダウンロードします。 +[ダウンロードURL][downlink]にアクセスし、32bitシステムであればgo1.4.2.linux-386.tar.gzを、64bitシステムであればgo1.2.2.linux-amd64.tar.gzをダウンロードします。 以下ではGoがインストールされたディレクトリを`$GO_INSTALL_DIR`と仮定します。 -`tar.gz`をインストールディレクトリに解凍します:`tar zxvf go1.0.3.linux-amd64.tar.gz -C $GO_INSTALL_DIR` +`tar.gz`をインストールディレクトリに解凍します:`tar zxvf go1.4.2.linux-amd64.tar.gz -C $GO_INSTALL_DIR` PATHを設定します。`export PATH=$PATH:$GO_INSTALL_DIR/go/bin` @@ -115,11 +119,11 @@ gvmはサードパーティが開発したGoのバージョン管理ツールで インストールが完了したあと、goをインストールすることができます: - gvm install go1.1 - gvm use go1.1 + gvm install go1.4.2 + gvm use go1.4.2 下のコマンドで、毎回gvm useをコールする手間を省くことができます: - gvm use go1.1 --default + gvm use go1.4.2 --default 上のコマンドを実行したあと、GOPATH、GOROOTなどの環境変数が自動的に設定されます。これで、直接利用することができます。 @@ -145,5 +149,4 @@ homebrewはMacで現在最も使用されているソフトウェア管理ツー * 前へ: [Goの環境設定](<01.0.md>) * 次へ: [GOPATHとワーキングディレクトリ](<01.2.md>) -[downlink]: http://code.google.com/p/go/downloads/list "Goインストールパッケージダウンロード" -[hg]: http://mercurial.selenic.com/downloads/ "Mercurialダウンロード" +[downlink]:http://golang.org/dl/ "Goインストールパッケージダウンロード" diff --git a/ja/01.2.md b/ja/01.2.md index 72a27153..a327a8fe 100644 --- a/ja/01.2.md +++ b/ja/01.2.md @@ -1,13 +1,17 @@ # 1.2 GOPATHとワーキングディレクトリ -## GOPATH設定 - go コマンドには重要な環境変数があります:$GOPATH1 +さきほどGoをインストールする際はGOPATH変数を設定する必要があるとご説明しました。Goはバージョン1.1から必ずこの変数を設定するようになっており、Goのインストールディレクトリと同じにはできません。このディレクトリは、GoのソースコードやGoの実行可能ファイル、並びにコンパイル済みのパッケージファイルを保存する為に使用します。そのためこのディレクトリには3つのサブディレクトリが存在します:src、bin、pkgです。 - *(注:これはGoのインストールディレクトリではありません。以下では筆者のワーキングディレクトリで説明します。ご自身のマシン上のワーキングディレクトリに置き換えてください。)* +## GOPATH設定 + go コマンドは、ある重要な環境変数に依存しています:$GOPATH1 + + Windowsシステムにおいて環境変数の形式は`%GOPATH%`です。この本の中では主にUnix形式を使用します。Windowsユーザは適時置き換えてください。 + + *(注:これはGoのインストールディレクトリではありません。以下では筆者のワーキングディレクトリで説明します。もし異なるディレクトリを使用する場合はGOPATHをあなたのワーキングディレクトリに置き換えてください。)* Unix に似た環境であれば大体以下のような設定になります: ```sh - export GOPATH=/home/apple/mygo +export GOPATH=/home/apple/mygo ``` 上のディレクトリを新たに作成し、上の一行を`.bashrc`または`.zshrc`もしくは自分の`sh`の設定ファイルに加えます。 @@ -26,28 +30,29 @@ GOPATHは複数のディレクトリを許容します。複数のディレク 以降私はすべての例でmygoを私のgopathディレクトリとします。 -## アプリケーションディレクトリ構成 -パッケージとディレクトリの作成:$GOPATH/src/mymath/sqrt.go(パッケージ名:"mymath") +## ソースコードディレクトリ構成 +GOPATH内のsrcディレクトリはこれから開発するプログラムにとってメインとなるディレクトリです。全てのソースコードはこのディレクトリに置くことになります。一般的な方法では一つのプロジェクトが一つのディレクトリが割り当てられます、例えば:$GOPATH/src/mymath はmymathというアプリケーションパッケージか実行アプリケーションになります。これはpackageがmainかそうでないかによって決定します。mainであれば実行可能アプリケーションで、そうでなければアプリケーションパッケージになります。これに関してはpackageを後ほどご紹介する予定です。 -以後私が新規に作成するアプリケーションまたはコードパッケージはsrcディレクトリに新規ディレクトリを作成します。ディレクトリ名はほぼコードパッケージの名前です。当然ネストしたディレクトリもありえます、例えば、srcの下にディレクトリ $GOPATH/src/github.com/astaxie/beedbというようなディレクトリを作成すると、このパッケージのパスは"github.com/astaxie/beedb"になります。パッケージ名は最後のディレクトリであるbeedbです。 -以下のコードを実行します。 +新しくアプリケーションやソースパッケージを作成するときは、srcディレクトリの中にディレクトリを作るところから始めます。ディレクトリ名は一般的にソースパッケージ名になります。もちろんネストしたディレクトリも可能です。例えばsrcの中に$GOPATH/src/github.com/astaxie/beedbというディレクトリを作ったとすると、このパッケージパスは"github.com/astaxie/beedb"になり、パッケージ名は最後のディレクトリであるbeedbになります。 + +以下ではmymathを例にどのようにアプリケーションパッケージをコーディングするかご説明します。以下のコードを実行します。 ```sh - cd $GOPATH/src - mkdir mymath +cd $GOPATH/src +mkdir mymath ``` sqrt.goというファイルを作成し、内容を以下のようにします。 ```go - // $GOPATH/src/mymath/sqrt.goコードは以下の通り: - package mymath +// $GOPATH/src/mymath/sqrt.goコードは以下の通り: +package mymath - func Sqrt(x float64) float64 { - z := 0.0 - for i := 0; i < 1000; i++ { - z -= (z*z - x) / (2 * x) - } - return z +func Sqrt(x float64) float64 { + z := 0.0 + for i := 0; i < 1000; i++ { + z -= (z*z - x) / (2 * x) } + return z +} ``` このように私のアプリケーションパッケージディレクトリとコードが作成されました。注意:一般的にpackageの名前とディレクトリ名は一致させるべきです。 @@ -60,49 +65,58 @@ sqrt.goというファイルを作成し、内容を以下のようにします インストールが終われば、以下のディレクトリに入り ```sh - cd $GOPATH/pkg/${GOOS}_${GOARCH} - //以下のファイルが現れるはずです。 - mymath.a +cd $GOPATH/pkg/${GOOS}_${GOARCH} +//以下のファイルが現れるはずです。 +mymath.a ``` この.aファイルはアプリケーションパッケージです。ならば我々はどのように実行できるでしょうか? -次にアプリケーション・プログラムを作成して実行します。 +次にアプリケーション・プログラムを作成してこのアプリケーションパッケージをコールします。 アプリケーションパッケージmathappを作ります。 ```sh - cd $GOPATH/src - mkdir mathapp - cd mathapp - vim main.go +cd $GOPATH/src +mkdir mathapp +cd mathapp +vim main.go ``` -// `$GOPATH/src/mathapp/main.go`コード: + +`$GOPATH/src/mathapp/main.go`コード: ```go - package main +package main - import ( - "mymath" - "fmt" - ) +import ( + "mymath" + "fmt" +) - func main() { - fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2)) - } +func main() { + fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2)) +} ``` -どのようにプログラムをコンパイルするのでしょうか?このアプリケーションディレクトリに入り、`go build`を実行すれば、このディレクトリの下にmathappの実行可能ファイルが生成されます。 +このパッケージは`main`であることが分かると思います。importにおいてコールするパッケージは`mymath`であり、これが`$GOPATH/src`のパスに対応します。もしネストしたディレクトリであれば、importの中でネストしたディレクトリをインポートします。例えばいくつものGOPATHがあった場合も同じで、Goは自動的に複数の`$GOPATH/src`の中から探し出します。 + +さて、どのようにプログラムをコンパイルするのでしょうか?このアプリケーションディレクトリに入り、`go build`を実行すれば、このディレクトリの下にmathappの実行可能ファイルが生成されます。 ```sh - ./mathapp +./mathapp ``` + 以下のように出力されます。 ```sh - Hello, world. Sqrt(2) = 1.414213562373095 +Hello, world. Sqrt(2) = 1.414213562373095 ``` -どのようにアプリケーションをインストールするのでしょうか。このディレクトリに入り、`go install`を実行します。すると、$GOPATH/bin/の下に実行可能ファイルmathappが作成されますので、コマンドラインから以下のように入力することで実行することができます。 - mathapp +どのようにアプリケーションをインストールするのでしょうか。このディレクトリに入り、`go install`を実行すると、$GOPATH/bin/の下に実行可能ファイルmathappが作成されます。`$GOPATH/bin`が我々のPATHに追加されていることを思い出して下さい、コマンドラインから以下のように入力することで実行することができます。 + +```sh +mathapp +``` この場合も以下のように出力されます。 Hello, world. Sqrt(2) = 1.414213562373095 + +ここではどのように実行可能アプリケーションをコンパイル/インストールし、ディレクトリ構造を設計するかについてご紹介しました。 ## リモートパッケージの取得 go言語はリモートパッケージを取得するツール`go get`を持っています。現在go getは多数のオープンソースリポジトリをサポートしています(github、googlecode、bitbucket、Launchpad) @@ -156,8 +170,6 @@ go getは以下のような手順を踏みます。まずはじめにソース 上述の構成から明確に判断できるのは、binディレクトリの下にコンパイル後の実行可能ファイルが保存され、pkgの下に関数パッケージが保存され、srcの下にアプリケーションのソースコードが保存されているということです。 - - - - -[1] Windowsシステムの環境変数の形式は`%GOPATH%`です。本書では主にUnix形式を使いますので、Windowsユーザは適時自分の環境に置き換えてください。 ## links * [目次]() * 前へ: [GOのインストール](<01.1.md>) diff --git a/ja/01.3.md b/ja/01.3.md index f2be5d30..0ca8fa34 100644 --- a/ja/01.3.md +++ b/ja/01.3.md @@ -4,7 +4,7 @@ Go言語は完全なコマンド操作ツールセットを持つ言語です。コマンドラインで`go`を実行することでそれらを確認することができます: - ![](images/1.3.go.png?raw=true) + ![](images/1.1.mac.png?raw=true) 図1.3 Goコマンドで詳細情報を表示 @@ -12,7 +12,7 @@ ## go build - このコマンドは主にコンパイルテストに用いられます。パッケージのコンパイル作業中、もし必要であれば、同時に関連パッケージもコンパイルすることができます。 + このコマンドは主にソースコードのコンパイルに用いられます。パッケージのコンパイル作業中、もし必要であれば、同時に関連パッケージもコンパイルすることができます。 - もし普通のパッケージであれば、我々が1.2章で書いた`mypath`パッケージのように、`go build`を実行したあと、何のファイルも生成しません。もし`$GOPATH/pkg`の下に対応するファイルを生成する必要があれば、`go install`を実行してください。 @@ -35,9 +35,28 @@ `go build`の際、システム名の末尾のファイルから選択的にコンパイルすることができます(Linux、Darwin、Windows、Freebsd) +引数の紹介 + +- `-o` 出力するファイル名を指定します。パスが含まれていても構いません。例えば `go build -o a/b/c` +- `-i` パッケージをインストールします。コンパイル+`go install` +- `-a` すでに最新であるパッケージを全て更新します。ただし標準パッケージには適用されません。 +- `-n` 実行が必要なコンパイルコマンドを出力します。ただし、実行はされません。これにより低レイヤーで一体何が実行されているのかを簡単に知る事ができます。 +- `-p n` マルチプロセスで実行可能なコンパイル数を指定します。デフォルトはCPU数です。 +- `-race` コンパイルを行う際にレースコンディションの自動検出を行います。64bitマシンでのみ対応しています。 +- `-v` 現在コンパイル中のパッケージ名を出力します。 +- `-work` コンパイル時の一時ディレクトリ名を出力し、すでに存在する場合は削除しなくなります。 +- `-x` 実行しているコマンドを出力します。`-n`の結果とよく似ていますが、この場合は実行します。 +- `-ccflags 'arg list'` オプションを5c, 6c, 8cに渡してコールします。 +- `-compiler name` コンパイラを指定します。gccgoか、またはgcです。 +- `-gccgoflags 'arg list'` オプションをgccgoリンカに渡してコールします。 +- `-gcflags 'arg list'` オプションを5g, 6g, 8gに渡してコールします +- `-installsuffix suffix` デフォルトのインストールパッケージと区別するため、このサフィックスを利用して依存するパッケージをインストールします。`-race`をオプションに指定した場合はデフォルトで`-installsuffix race`が有効になっています。`-n`コマンドで確かめることができますよ。 +- `-ldflags 'flag list'` オプションを5l, 6l, 8lに渡してコールします。 +- `-tags 'tag list'` コンパイル時にこれらのtagをつけることができます。tagの詳細な制限事項に関しては [Build Constraints](http://golang.org/pkg/go/build/) を参考にして下さい。 + ## go clean - このコマンドは現在のソースコードパッケージのなかでコンパイラが生成したファイルを取り除く操作を行います。これらのファイルはすなわち: + このコマンドは現在のソースコードパッケージと関連するソースパッケージのなかでコンパイラが生成したファイルを取り除く操作を行います。これらのファイルはすなわち: _obj/ 旧objectディレクトリ、MakeFilesが作成する。 _test/ 旧testディレクトリ,Makefilesが作成する。 @@ -49,14 +68,39 @@ DIR(.exe) go buildが作成する。 DIR.test(.exe) go test -cが作成する。 MAINFILE(.exe) go build MAINFILE.goが作成する。 + *.so SWIG によって生成される。 私は基本的にこのコマンドを使ってコンパイルファイルを掃除します。ローカルでテストを行う場合これらのコンパイルファイルはシステムと関係があるだけで、コードの管理には必要ありません。 + $ go clean -i -n + cd /Users/astaxie/develop/gopath/src/mathapp + rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe + rm -f /Users/astaxie/develop/gopath/bin/mathapp + +引数紹介 + +- `-i` go installがインストールするファイル等の、関係するインストールパッケージと実行可能ファイルを取り除きます。 +- `-n` 実行する必要のある削除コマンドを出力します。ただし実行はされません。これにより低レイヤで何が実行されているのかを簡単に知ることができます。 +- `-r` importによってインポートされたパッケージを再帰的に削除します。 +- `-x` 実行される詳細なコマンドを出力します。`-n`出力の実行版です。 + ## go fmt 読者にC/C++の経験があればご存知かもしれませんが、コードにK&Rスタイルを選択するかANSIスタイルを選択するかは常に論争となっていました。goでは、コードに標準のスタイルがあります。すでに培われた習慣やその他が原因となって我々は常にANSIスタイルまたはその他のより自分にあったスタイルでコードを書いて来ました。これは他の人がコードを閲覧する際に不必要な負担を与えます。そのためgoはコードのスタイルを強制し(例えば左大括弧はかならず行末に置く)、このスタイルに従わなければコンパイルが通りません。整形の時間の節約するため、goツールは`go fmt`コマンドを提供しています。これはあなたの書いたコードを整形するのに役立ちます。あなたの書いたコードは標準のスタイルに修正されますが、我々は普段このコマンドを使いません。なぜなら開発ツールには一般的に保存時に自動的に整形を行ってくれるからです。この機能は実際には低レイヤでは`go fmt`を呼んでいます。この次の章で2つのツールをご紹介しましょう。この2つのツールはどれもファイルを保存する際に`go fmt`機能を自動化させます。 ->go fmtコマンドの使用では、多くの場合はgofmtを使用しますが、-wオプションが必要になります。さもなければ、整形結果はファイルに書き込まれません。gofmt -w src、ですべての項目を整形することができます。 +go fmtコマンドを使うにあたって実際にはgofmtがコールますが、-wオプションが必要になります。さもなければ、整形結果はファイルに書き込まれません。gofmt -w -l src、ですべての項目を整形することができます。 + +go fmtはgofmtの上位レイヤーのパッケージされたコマンドです。より個人的なフォーマットスタイルが欲しい場合は [gofmt](http://golang.org/cmd/gofmt/) を参考にしてください。 + +gofmtの引数紹介 + +- `-l` フォーマットする必要のあるファイルを表示します。 +- `-w` 修正された内容を標準出力に書き出すのではなく、直接そのままファイルに書き込みます。 +- `-r` “a[b:len(a)] -> a[b:]”のような重複したルールを追加します。大量に変換を行う際に便利です。 +- `-s` ファイルのソースコードを簡素化します。 +- `-d` ファイルに書き込まず、フォーマット前後のdiffを表示します。デフォルトはfalseです。 +- `-e` 全ての文法エラーを標準出力に書き出します。もしこのラベルを使わなかった場合は異なる10行のエラーまでしか表示しません。 +- `-cpuprofile` テストモードをサポートします。対応するするcpufile指定のファイルに書き出します。 ## go get @@ -69,10 +113,21 @@ そのため、`go get`を正常に動作させるためには、あらかじめ適切なソースコード管理ツールがインストールされていると同時にこれらのコマンドがあなたのPATHに入っていなければなりません。実は`go get`はカスタムドメインの機能をサポートしています。具体的な内容は`go help remote`を参照ください。 +引数紹介: + +- `-d` ダウンロードするだけでインストールしません。 +- `-f` `-u`オプションを与えた時だけ有効になります。`-u`オプションはimportの中の各パッケージが既に取得されているかを検証しなくなります。ローカルにforkしたパッケージに対して特に便利です。 +- `-fix` ソースコードをダウンロードするとまずfixを実行してから他の事を行うようになります。 +- `-t` テストを実行する為に必要となるパッケージも同時にダウンロードします。 +- `-u` パッケージとその依存パッケージをネットワークから強制的に更新します。 +- `-v` 実行しているコマンドを表示します。 + ## go install このコマンドは実際には内部で2ステップの操作に分かれます。第1ステップはリザルトファイルの生成(実行可能ファイルまたはaパッケージ)、第2ステップはコンパイルし終わった結果を`$GOPATH/pkg`または`$GOPATH/bin`に移動する操作です。 +引数は`go build`のコンパイルオプションをサポートしています。みなさんは`-v`オプションだけ覚えていただければ結構です。これにより低レイヤーの実行状況をいつでも確認することができます。 + ## go test このコマンドを実行すると、ソースコードディレクトリ以下の`*_test.go`ファイルが自動的にロードされ、テスト用の実行可能ファイルが生成/実行されます。出力される情報は以下のようなものになります @@ -84,10 +139,44 @@ デフォルトの状態で、オプションを追加する必要はありません。自動的にあなたのソースコードパッケージ以下のすべてのtestファイルがテストされます。もちろんオプションを追加しても構いません。詳細は`go help testflag`を確認してください。 -## go doc +ここでは良く使われるオプションについてご紹介します: - (1.2rc1 から go doc コマンドはなくなり、 godoc コマンドのみになります) - 多くの人がgoはいかなるサードパーティドキュメントも必要としないと言っています。なぜなら例えばchmマニュアルのように(もっとも私はすでに[chmマニュアル](https://github.com/astaxie/godoc)を作っていますが)、この中にすでに非常に協力なドキュメントツールが入っているからです。 +- `-bench regexp` 指定したbenchmarksを実行します。例えば `-bench=.` +- `-cover` テストカバー率を起動します。 +- `-run regexp` regexpにマッチする関数だけを実行します。例えば `-run=Array` とすることで名前がArrayから始まる関数だけを実行します。 +- `-v` テストの詳細なコマンドを表示します。 + +## go tool +`go tool`にはいくつものコマンドがあります。ここでは2つだけご紹介します。fixと vetです。 + +- `go tool fix .` は以前の古いバージョンを新しいバージョンに修復します。例えば、go1以前の古いバージョンのコードをgo1に焼き直したり、APIを変化させるといったことです。 +- `go tool vet directory|files` はカレントディレクトリのコードが正しいコードであるか分析するために使用されます。例えばfmt.Printfをコールする際のオプションが正しくなかったり、関数の途中でreturnされたことによって到達不可能なコードが残っていないかといった事です。 + +## go generate +このコマンドはGo1.4になって初めてデザインされました。コンパイル前にある種のコードを自動で生成する目的に使用されます。`go generate`と`go build`は全くことなるコマンドです。ソースコード中の特殊なコメントをを分析することで、対応するコマンドを実行します。これらのコマンドは明確に何の依存も存在しません。この機能を使用する場合には必ず次の事を念頭に置いてください。`go generate`はあなたの為に存在します。あなたのパッケージを使用する誰かの為のものではありません。これはある一定のコードを生成するためにあります。 + +簡単な例をご紹介します。例えば我々が度々`yacc`を使ってコードを生成していたとしましょう。その場合以下のようなコマンドをいつも使用することになります: + + go tool yacc -o gopher.go -p parser gopher.y + +-o は出力するファイル名を指定します。-pはパッケージ名を指定します。これは単独のコマンドであり、もし`go generate`によってこのコマンドを実行する場合は当然ディレクトリの任意の`xxx.go`ファイルの任意の位置に以下のコメントを一行追加します。 + + //go:generate go tool yacc -o gopher.go -p parser gopher.y + +注意すべきは、`//go:generate`に空白が含まれていない点です。これは固定のフォーマットで、ソースファイルを舐める時はこのフォーマットに従って判断されます。 + +これにより以下のようなコマンドによって、生成・コンパイル・テストを行うことができます。もし`gopher.y`ファイルに修正が発生した場合は、再度`go generate`を実行することでファイルを上書きすればよいことになります。 + + $ go generate + $ go build + $ go test + + +## godoc + +Go1.2バージョンより以前は`go doc`コマンドがサポートされていましたが、今後は全てgodocコマンドに移されました。このようにインストールします`go get golang.org/x/tools/cmd/godoc` + +多くの人がgoにはサードパーティのドキュメントが必要無いと謳っています。なぜなら例えばchmハンドブックのように(もっとも私はすでに[chmマニュアル](https://github.com/astaxie/godoc)を作っていますが)、この中にはとても強力なドキュメントツールが含まれているからです。 どのように対応するpackageのドキュメントを確認すればよいでしょうか? 例えばbuiltinパッケージであれば、`go doc builtin`と実行します。 @@ -101,13 +190,12 @@ goは他にも様々なツールを提供しています。例えば以下のツール - go fix は以前の古いバージョンのコードを新しいバージョンに復元するために使われます。例えばgo1の前の古いバージョンのコードをgo1に移動させます。 go version はgoの現在のバージョンを確認します。 go env は現在のgoの環境変数を確認します。 go list は現在インストールされている全てのpackageをリストアップします。 go run はGoプログラムのコンパイルと実行を行います。 -以上これらのツールはまだ多くのオプションがあり、ひとつひとつはご紹介しませんが、ユーザは`go help コマンド`で更に詳しいヘルプ情報を取得することができます。 +これらのツールはまだ多くのオプションがあり、ひとつひとつはご紹介しませんが、ユーザは`go help コマンド`で更に詳しいヘルプ情報を取得することができます。 ## links diff --git a/ja/01.4.md b/ja/01.4.md index 04f2123f..51268e18 100644 --- a/ja/01.4.md +++ b/ja/01.4.md @@ -47,17 +47,11 @@ **LiteIDEインストール設定** * LiteIDEインストール - * ダウンロード + * ダウンロード http://sourceforge.net/projects/liteide/files/> * ソースコード まずGo言語環境をインストールし、その後オペレーティングシステムにしたがってLiteIDEの対応圧縮ファイルを直接解凍すれば使用できます。 -* Gocodeのインストール - - Go言語の入力自動補完を起動するにはGocodeをインストールする必要があります: - - go get -u github.com/nsf/gocode - * コンパイル環境設定 自身のシステムの要求にしたがってLiteIDEが現在使用している環境変数を切り替えまたは設定します。 @@ -99,7 +93,7 @@ ## Sublime Text - ここではSublime Text 2(以下「Sublime」)+GoSublime+gocode+Margoの組み合わせをご紹介します。なぜこの組み合わせなのでしょうか? + ここではSublime Text 2(以下「Sublime」)+GoSublimeの組み合わせをご紹介します。なぜこの組み合わせなのでしょうか? - コード表示の自動化、以下の図の通り @@ -158,30 +152,6 @@ ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime - 5. プロジェクトのサポート、sublimeにプロジェクト自身のpkgライブラリのサポートを示します。二種類の基本的な実装があります - - ひとつは gosublime プラグインの `Setting - user` の設定 - - { - "env": { "GOPATH": "$HOME/golang:$GS_GOPATH" } - } - - `$GS_GOPATH` は gosublime の仮想的な環境変数です。自動的に`.go`ファイルが存在する `~/go/src` を探し出すことで、 `~/go/` をプロジェクトのパスと推測し、自動的に `GOPATH` を適用します。(注意:このような方法ではsublimeにおいてオリジナルのGOPATHを上書きしてしまいます。もしこの設定でエラーが発生した場合は、GOPATHに関連した問題が発生していることになります) - - もうひとつは、sublime プロジェクトの保存です。 project_name.sublime-project を修正して項目を追加します - - - "settings": { - "GoSublime": { - "env": { - "GOPATH": "$HOME/golang/pwd" // ここをプロジェクトのパスに修正 - } - } - }, - - "folders"{... - - ## Vim Vimはviから発展したテキストエディタです。コード補完、コンパイルまたエラージャンプなど、プログラミングに特化した機能が豊富です。広くプログラマに使用されています。 @@ -203,7 +173,7 @@ Vimはviから発展したテキストエディタです。コード補完、コ go get -u github.com/nsf/gocode - gocodeはデフォルトで`$GOBIN`の下にインストールされています。 + gocodeはデフォルトで`$GOPATH/bin`の下にインストールされています。 4. [Gocode](https://github.com/nsf/gocode/)を設定します。 @@ -217,11 +187,11 @@ Vimはviから発展したテキストエディタです。コード補完、コ propose-builtins true lib-path "/home/border/gocode/pkg/linux_amd64" - >gocode setの2つのパラメータの意味を説明します: + >gocode setの2つのパラメータの意味を説明します: > - >propose-builtins:はGoのビルトイン関数を補完するかです。タイプは定数です。デフォルトはfalseで、表示しません。 + >propose-builtins:はGoのビルトイン関数を補完するかです。タイプは定数です。デフォルトはfalseで、表示しません。 > - >lib-path:デフォルトで、gocodeは**$GOPATH/pkg/$GOOS_$GOARCH**と**$GOROOT/pkg/$GOOS_$GOARCH**ディレクトリのパッケージを検索するだけです。当然この設定には私達の外側のlibを検索できるようパスを設定することができます。 + >lib-path:デフォルトで、gocodeは**$GOPATH/pkg/$GOOS_$GOARCH**と**$GOROOT/pkg/$GOOS_$GOARCH**ディレクトリのパッケージを検索するだけです。当然この設定には私達の外側のlibを検索できるようパスを設定することができます。 5. おめでとうございます。インストール完了です。あなたは今から`:e main.go`でGoで開発する面白さを体験することができます。 diff --git a/ja/02.2.md b/ja/02.2.md index 77ef58f1..94ef3f14 100644 --- a/ja/02.2.md +++ b/ja/02.2.md @@ -1,469 +1,484 @@ -# 2.2 Go基礎 - -この節では変数、定数、Goの内部クラスの定義と、Goプログラムの設計におけるテクニックをご紹介します。 - -## 変数の定義 - -Go言語では変数は数多くの方法で定義されます。 - -`var`キーワードを使用することはGoの最も基本的な変数の定義方法です。C言語と異なり、Goでは変数の型を変数の後に置きます。 - - //"variableName"という名前で定義します。型は"type"です。 - var variableName type - -複数の変数を定義します。 - - //すべて"type"型の3つの変数を定義します。 - var vname1, vname2, vname3 type - -変数を定義し、初期化します。 - - //"variableName"の変数を"value"で初期化します。型は"type"です。 - var variableName type = value - -複数の変数を同時に初期化します。 - - /* - すべて"type"型の3つの変数を定義し、それぞれ個別に初期化を行います。 - vname1はv1,vname2はv2,vname3はv3 - */ - var vname1, vname2, vname3 type= v1, v2, v3 - -あなたは上述の定義が面倒だと思いますか?大丈夫、Go言語の設計者もわかっています。少し簡単に書くこともできます。直接型の宣言を無視することができるので、上のコードはこのようにも書けます: - - /* - 3つの変数を定義し、それぞれ個別に初期化する。 - vname1はv1,vname2はv2,vname3はv3 - このあとGoは代入される値の肩に従ってそれぞれ初期化を行います。 - */ - var vname1, vname2, vname3 = v1, v2, v3 - -これでもまだ面倒ですか?ええ、私もそう思います。更に簡単にしてみましょう。 - - /* - 3つの変数を定義し、それぞれ個別に初期化します。 - vname1はv1,vname2はv2,vname3はv3 - コンパイラは初期化する値に従って自動的にふさわしい型を導き出します。 - */ - vname1, vname2, vname3 := v1, v2, v3 - -これなら非常に簡潔になったでしょう?`:=`の記号は`var`と`type`に直接取って代わるものです。これらの形式を短縮宣言と呼びます。ただしこれにはひとつ制限があります。これらは関数の内部でしか使用できません。関数の外で使用するとコンパイルが通らなくなります。そのため、一般的には`var`方式でグローバル変数が定義されます。 - -`_`(アンダースコア)は特別な変数名です。どのような値もすべて捨てられてしまいます。この例では`35`という値を`b`に与えますが、同時に`34`は失われてしまいます。 - - _, b := 34, 35 - -Goはすでに宣言されている未使用の変数をコンパイル時にエラーとして出力します。例えば下のコードはエラーを一つ生成します。`i`は宣言されましたが使用されていません。 - - package main - - func main() { - var i int - } - -## 定数 - -いわゆる定数というのは、プログラムがコンパイルされる段階で値が決定されます。また、プログラムが実行される時には値の変更は許されません。定数には数値、bool値または文字列等の型を定義することができます。 - -この文法は以下の通りです: - - const constantName = value - //もし必要であれば、定数の型を明示することもできます: - const Pi float32 = 3.1415926 - -ここでは定数の宣言の例を示します: - - const Pi = 3.1415926 - const i = 10000 - const MaxThread = 10 - const prefix = "astaxie_" - -Go の定数は一般的なプログラミング言語と異なり、かなり多くの小数点以下の桁を指定することができます(たとえば200桁など)、 -float32に自動的な32bitへの短縮を指定したり、float64に自動的な64bitへの短縮を指定するには[リンク](http://golang.org/ref/spec#Constants)をご参照ください。 - -## ビルトイン基本型 - -### Boolean - -Goではbool値の型は`bool`です。値は`true`もしくは`false`です。デフォルト値は`false`です。 - - // コード例 - var isActive bool // グローバル変数の宣言 - var enabled, disabled = true, false // 型を省略した宣言 - func test() { - var available bool // 通常の宣言 - valid := false // 短縮宣言 - available = true // 代入操作 - } - - -### 数値型 - -整数型には符号付きと符号無しの2つがあります。Goはまた`int`と`uint`をサポートしています。この2つの型の長さは同じですが、実際の長さは異なるコンパイラによって決定されます。~~現在のgccとgccgoコンパイラは32bitと64bitプラットフォーム上では常に32bitで`int`と`uint`を表示しますが、将来64bitプラットフォーム上では64bitまで拡張されるかもしれません~~。Goでは直接bit数を指定できる型もあります:`rune`, `int8`, `int16`, `int32`, `int64`と`byte`, `uint8`, `uint16`, `uint32`, `uint64`です。この中で`rune`は`int32`のエイリアスです。`byte`は`uint8`のエイリアスです。 - ->注意しなければならないのは、これらの型の変数間は相互に代入または操作を行うことができないということです。コンパイル時にコンパイラはエラーを発生させます。 -> ->下のコードはエラーが発生します。:invalid operation: a + b (mismatched types int8 and int32) -> ->> var a int8 - ->> var b int32 - ->> c:=a + b -> ->また、intの長さは32bitですが、intとint32もお互いに利用することはできません。 - -浮動小数点の型には`float32`と`float64`の二種類があります(`float`型はありません。)。デフォルトは`float64`です。 - -これで全てですか?No! Goは複素数もサポートしています。このデフォルト型は`complex128`(64bit実数+64bit虚数)です。もしもう少し小さいのが必要であれば、`complex64`(32bit実数+32bit虚数)もあります。複素数の形式は`RE + IMi`です。この中で`RE`が実数部分、`IM`が虚数部分になります。最後の`i`は虚数単位です。以下に複素数の使用例を示します: - - var c complex64 = 5+5i - //output: (5+5i) - fmt.Printf("Value is: %v", c) - - -### 文字列 - -前の章で述べた通り、Goの文字列はすべて`UTF-8`コードが採用されています。文字列は一対のダブルクォーテーション(`""`)またはバッククォート(`` ` `` `` ` ``)で括られることで定義されます。この型は`string`です。 - - //コード例 - var frenchHello string // 文字列変数の宣言の一般的な方法 - var emptyString string = "" // 文字列変数を一つ宣言し、空文字列で初期化する。 - func test() { - no, yes, maybe := "no", "yes", "maybe" // 短縮宣言、同時に複数の変数を宣言 - japaneseHello := "Konichiwa" // 同上 - frenchHello = "Bonjour" // 通常の代入 - } - -Goの文字列は変更することができません。例えば下のコードはコンパイル時にエラーが発生します。:cannot assign to s[0] - - var s string = "hello" - s[0] = 'c' - - -ただし、本当に変更したくなったらどうしましょうか?ここでは以下のコードで実現します: - - s := "hello" - c := []byte(s) // 文字列 s を []byte 型にキャスト - c[0] = 'c' - s2 := string(c) // もう一度 string 型にキャストし直す - fmt.Printf("%s\n", s2) - - -Goでは`+`演算子を使って文字列を連結することができます: - - s := "hello," - m := " world" - a := s + m - fmt.Printf("%s\n", a) - -文字列の修正もこのように書けます: - - s := "hello" - s = "c" + s[1:] // 文字列を変更することはできませんが、スライスは行えます。 - fmt.Printf("%s\n", s) - -もし複数行の文字列を宣言したくなったらどうしましょうか?この場合`` ` ``で宣言することができます: - - m := `hello - world` - -`` ` `` で括られた文字列はRaw文字列です。すなわち、文字列はコード内の形式がそのままプリント時の形式になります。文字列の変更はありません。改行はそのまま出力されます。例えばこの例では以下のように出力されます: - - hello - world - -### エラー型 -Goにはビルトインの`error`型があります。専らエラー情報の処理に使用されます。Goの`package`の中にはエラー処理を行う`errors`というパッケージがあります。 - - err := errors.New("emit macho dwarf: elf header corrupted") - if err != nil { - fmt.Print(err) - } - -### Goデータの低レイヤの保存 - -下の図は[Russ Cox Blog](http://research.swtch.com/)の中の一文で紹介されている[Goデータ構造](http://research.swtch.com/godata)の文章です。これらの基本型は低レイヤでメモリを分配し、対応する値を保存していることが見て取れるとおもいます。 - -![](images/2.2.basic.png?raw=true) - -図2.1 Goデータ形式の保存 - -## テクニック - -### グループ化による宣言 - -Go言語では、複数の定数・変数を宣言する場合、または複数のパッケージをインポートする場合、グループ化による方法で宣言することができます。 - -例えば以下のコード: - - import "fmt" - import "os" - - const i = 100 - const pi = 3.1415 - const prefix = "Go_" - - var i int - var pi float32 - var prefix string - -グループ化によって以下のような形式になります: - - import( - "fmt" - "os" - ) - - const( - i = 100 - pi = 3.1415 - prefix = "Go_" - ) - - var( - i int - pi float32 - prefix string - ) - ->他の値や`iota`に設定されているものを除いて、各`const`グループのはじめの定数はデフォルトで0となります。二番目以降の定数は前の定数の値がデフォルト値となります。もし前の定数の値が`iota`であれば、直後の値も`iota`になります。 - -### iota列挙型 - -Goでは`iota`というキーワードがあります。このキーワードは`enum`を宣言する際に使用されます。このデフォルト値は0からはじまり、順次1が追加されます: - - const( - x = iota // x == 0 - y = iota // y == 1 - z = iota // z == 2 - w // 定数の宣言で値を省略した場合、デフォルト値は前の値と同じになります。ここではw = iotaと宣言していることと同じになりますので、w == 3となります。実は上のyとzでもこの"= iota"は省略することができます。 - ) - - const v = iota // constキーワードが出現する度に、iotaは置き直されます。ここではv == 0です。 - - const ( - e, f, g = iota, iota, iota //e=0,f=0,g=0 iotaの同一行は同じです - ) - -### Goプログラムのデザインルール -Goがこのように簡潔なのは、それがいくつかのデフォルトの行為を持っているからです: -- 大文字で始まる変数はエクスポート可能です。つまり、他のパッケージから読むことができる、パブリックな変数だということです。対して小文字で始まる変数はエクスポートできません。これはプライベート変数です。 -- 大文字で始まる関数も同じです。`class`の中で`public`キーワードによってパブリック関数となっているのと同じです。対して小文字で始まる関数は`private`キーワードのプライベート関数です。 - -## array、slice、map - -### array -`array`は配列です。この定義は以下のようになります: - - var arr [n]type - -`[n]type`の中で、`n`は配列の長さを表しています。`type`は保存する要素の型を示しています。配列に対する操作は他の言語とよく似ていて、どれも`[]`を通して値の取得および代入を行います。 - - var arr [10]int // int型の配列を宣言します。 - arr[0] = 42 // 配列のインデックスは0からはじまります。 - arr[1] = 13 // 代入操作 - fmt.Printf("The first element is %d\n", arr[0]) // データを取得して、42を返します。 - fmt.Printf("The last element is %d\n", arr[9]) //値が代入されていない最後の要素を返します。デフォルトでは0が返ります。 - -長さも配列の一部ですので、`[3]int`と`[4]int`は異なる型になります。配列も長さを変えることはできません。配列間の代入は値渡しです。つまり、一つの配列が関数の引数となった場合、渡されるのは実はこの配列のコピーであり、ポインタではありません。もしポインタを使いたい場合は、この後にご紹介する`slice`型をご利用ください。 - -配列はもうひとつの`:=`で宣言することができます。 - - a := [3]int{1, 2, 3} // 長さが3のintの配列を宣言します。 - - b := [10]int{1, 2, 3} // 長さが10のint配列を宣言します。この中で3つの要素の初期値は1、2、3で、そのほかのデフォルトは0です。 - - c := [...]int{4, 5, 6} // 長さを`...`で省略することもできます。Goは自動で要素数から長さを計算します。 - -もしあなたが「配列に配列を込めたい場合は実現できますか?」と問うならば、当然ですとも、とお応えしましょう。Goはネストした配列をサポートしています。例えば下のコードでは二次元配列を宣言しています: - - // 二次元配列を一つ宣言します。この配列は2つの配列を要素としており、各配列には4つのint型の要素が含まれます。 - doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} - - // 上の宣言は簡略化できます。直接内部の型を省略しています。 - easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} - -配列の状態は以下のとおりです: - -![](images/2.2.array.png?raw=true) - -図2.2 多次元配列のマッピング関係 - - -### slice - -多くのアプリケーションでは、配列はあまりわたしたちの要求を満たしてはくれません。配列を初期化する場合、どれぐらいの大きさの配列が必要かわからないからです。そのため、"動的な配列"が必要となります。Goではこのようなデータ構造を`slice`と呼びます。 - -`slice`は本当の意味での動的な配列ではありません。これは単なる参照型です。`slice`は常に低レイヤの`array`を指しています。`slice`の宣言も`array`と同様に長さを指定する必要はありません。 - - // arrayの宣言と同じですが、長さは必要ありません。 - var fslice []int - -次に`slice`を宣言すると同時にデータを初期化します: - - slice := []byte {'a', 'b', 'c', 'd'} - -`slice`はひとつの配列またはすでに存在する`slice`の中から宣言することができます。`slice`は`array[i:j]`で取得することができます。この中で`i`は配列の開始位置です。`j`は終了位置です。ただし`array[j]`は含みません。長さは`j-i`となります。 - - // 10個の要素を宣言します。要素の型はbyteの配列です。 - var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - - // byteを含む2つのsliceを宣言します - var a, b []byte - - // aポインタ配列の3つ目の要素から始まり、5つ目の要素まで - a = ar[2:5] - //現在aの持つ要素は:ar[2]、ar[3]とar[4]です。 - - // bは配列arのもう一つのsliceです。 - b = ar[3:5] - // bの要素は:ar[3]とar[4]です。 - ->`slice`と配列は宣言時に区別されますのでご注意ください:配列を宣言するとき、中括弧の中で配列の長さを明示するかまたは`...`で自動的に長さを計算します。一方`slice`を宣言する時は、中括弧内には文字はありません。 - -これらのデータ構造は以下のようになっています。 - -![](images/2.2.slice.png?raw=true) - -図2.3 sliceとarrayの対応関係図 - -sliceには便利な操作があります - - - `slice`のデフォルト開始位置は0です。`ar[:n]`などは`ar[0:n]`と等価です。 - - `slice`の2つ目の値のデフォルトは配列の長さです。`ar[n:]`は`ar[n:len(ar)]`等価です。 - - もし配列の中から直接`slice`を取り出す場合は、`ar[:]`というような形で指定することができます。なぜならデフォルトのはじめの値は0で2つ目は配列の長さだからです。すなわち、`ar[0:len(ar)]`と等価となります。 - -ここではより多くの`slice`の操作についていくつか例を挙げます: - - // 配列を宣言 - var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - // sliceを2つ宣言 - var aSlice, bSlice []byte - - // 便利な操作のデモンストレーション - aSlice = array[:3] // aSlice = array[0:3] と同じ。aSliceには以下の要素が含まれます: a,b,c - aSlice = array[5:] // aSlice = array[5:10] と同じ。aSliceには以下の要素が含まれます: f,g,h,i,j - aSlice = array[:] // aSlice = array[0:10] と同じ。この場合aSliceにはすべての要素が含まれます。 - - // sliceからsliceを取り出す - aSlice = array[3:7] // aSliceには以下の要素が含まれます: d,e,f,g,len=4,cap=7 - bSlice = aSlice[1:3] // bSlice にはaSlice[1], aSlice[2] が含まれそれぞれの要素は以下のとおりです: e,f - bSlice = aSlice[:3] // bSlice には aSlice[0], aSlice[1], aSlice[2] が含まれます。それぞれ以下のとおりです: d,e,f - bSlice = aSlice[0:5] // sliceのsliceに対してcapの範囲内で拡張することができます。この時bSliceには以下の要素が含まれます:d,e,f,g,h - bSlice = aSlice[:] // bSliceにはaSliceのすべての要素が含まれます: d,e,f,g - -`slice`は参照型ですので、この中の要素の値を変更すると、そのほかのすべての参照でも値が変更されます。たとえば上の`aSlice`と`bSlice`で、`aSlice`の中の要素を変更すると、`bSlice`の対応する値も同時に変更されます。 - -概念上では、`slice`は構造体です。この構造体には3つの要素が含まれます:  -- 一つはポインタです。配列中の`slice`が示す開始位置を指しています。 -- 長さ、つまり`slice`の長さです。 -- 最大の長さ、`slice`の開始位置から配列の最後の位置までの長さです。 - - Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - Slice_a := Array_a[2:5] - -上のコードの正しい保存構造は下の図に示す通りです。 - -![](images/2.2.slice2.png?raw=true) - -図2.4 sliceに対応する配列の情報 - -`slice`に対しては、いくつかの便利なビルトイン関数があります: - -- `len` `slice`の長さを取得します。 -- `cap` `slice`の最大容量を取得します。 -- `append` は`slice`に対して一つまたは複数の要素を追加します。その後`slice`と同じ型の`slice`を返します。 -- `copy` 関数`copy`はもとの`slice`の`src`を`dst`に要素をコピーし、コピーした要素の個数を返します。 - -注:`append`関数は`slice`が参照した配列の内容を変更し得ます。そのため、参照先と同一の配列の他の`slice`にも影響します。 -しかし`slice`の中に余分なスペースが無い(`(cap-len) == 0`)場合、動的なメモリから新たな配列空間が割り当てられます。返される`slice`配列のポインタはこの空間を指しています。また、もとの配列の内容は変わりません。この配列を参照している他の`slice`は影響を受けません。 - -### map - -`map`の概念もPythonのディクショナリです。この形式は`map[keyType]valueType`です。 - -下のコードをご覧ください。`map`の読み込みと代入は`slice`と似ています。`key`を通して操作します。ただ、`slice`の`index`は`int`型のみになります。`map`には多くの型があります。`int`でもかまいませんし、`string`や`==`と`!=`演算子が定義されている全ての型でもかまいません。 - - // keyを文字列で宣言します。値はintとなるディクショナリです。この方法は使用される前にmakeで初期化される必要があります。 - var numbers map[string]int - // もうひとつのmapの宣言方法 - numbers := make(map[string]int) - numbers["one"] = 1 //代入 - numbers["ten"] = 10 //代入 - numbers["three"] = 3 - - fmt.Println("3つ目の数字は: ", numbers["three"]) // データの取得 - // "3つ目の数字は: 3"という風に出力されます。 - -この`map`は我々が普段目にする表と同じです。左の列に`key`、右の列に値があります。 - -mapを使う段階で注意しなければならないことがいくつかあります: -- `map`は順序がありません。毎回`map`の出力は違ったものになるかもしれません。`index`で値を取得することはできず、かならず`key`を使うことになります。 -- `map`の長さは固定ではありません。`slice`と同じで、参照型の一種です。 -- ビルトインの`len`関数を`map`に適用すると、`map`がもつ`key`の個数を返します。 -- `map`の値は簡単に修正することができます。`numbers["one"]=11`というようにkeyが`one`のディクショナリの値を`11`に変えることができます。 -- `map`は他の基本型と異なり、thread-safeではありません。複数のgo-routineを扱う際には必ずmutex lockメカニズムを使用する必要があります。 - -`map`の初期化では`key:val`の方法で初期値を与えることができます。また同時に`map`には標準で`key`が存在するか確認する方法が存在します。 - -`delete`で`map`の要素を削除します: - - // ディクショナリを初期化します。 - rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 } - // mapは2つの戻り値があります。2つ目の戻り値では、もしkeyが存在しなければ、okはfalseに、存在すればokはtrueになります。 - csharpRating, ok := rating["C#"] - if ok { - fmt.Println("C# is in the map and its rating is ", csharpRating) - } else { - fmt.Println("We have no rating associated with C# in the map") - } - - delete(rating, "C") // keyがCの要素を削除します。 - - -上述の通り、`map`は参照型の一種ですので、もし2つの`map`が同時に同じポインタを指している場合、一つの変更で、もう一つにも変更が行われます。 - - m := make(map[string]string) - m["Hello"] = "Bonjour" - m1 := m - m1["Hello"] = "Salut" // この時、m["hello"]の値もすでにSalutになっています。 - - -### make, new操作 - -`make`はビルトイン型(`map`、`slice`および`channel`)のメモリの割り当てです。`new`は各型のメモリを割り当てます。 - -ビルトイン関数`new`は本質的には他の言語で使われる同名の関数と機能が同じです:`new(T)`はゼロサプレスされた`T`型のメモリ空間を割り当て、そのアドレスを返します。すなわち`*T`型の値です。Goの専門用語で言えば、ポインタを返すということです。新たに割り当てられた型`T`のゼロ値です。とても重要なことに: - ->`new`はポインタを返します。 - -ビルトイン関数`make(T, args)`と`new(T)`は異なる機能を持っています。makeは`slice`、`map`または`channel`を作成し、初期値(非ゼロ値)を持つ`T`型を返すのみで、`*T`ではありません。本質的には、この3つの型が異なる点はデータ構造を指し示す参照が使用される前に初期化されているということです。例えば、データ(内部`array`)を指し示すポインタ、長さ,容量による3点で記述される`slice`の各項目が初期化される前は、`slice`は`nil`です。`slice`, `map`, `channel`にとって、makeは内部のデータ構造を初期化し、適当な値で埋め尽くされます。 - ->`make`は初期化後の(非ゼロの)値を返します。 - -以下の図は`new`と`make`の違いについて詳細に解説しています。 - -![](images/2.2.makenew.png?raw=true) - -図2.5 makeとnewの低レイヤでのメモリの割り当て - -"ゼロ値"というのは何も空の値ではありません。これは一種の"変数が埋めらる前"のデフォルト値であり、通常は0です。 -それぞれの型のゼロ値は以下の通りです - - int 0 - int8 0 - int32 0 - int64 0 - uint 0x0 - rune 0 //runeの実際の型は int32 です。 - byte 0x0 // byteの実際の型は uint8 です。 - float32 0 //長さは 4 byte - float64 0 //長さは 8 byte - bool false - string "" - -## links - * [目次]() - * 前へ: [こんにちは、Go](<02.1.md>) - * 次へ: [フローと関数](<02.3.md>) +# 2.2 Go基礎 + +この節では変数、定数、Goの内部クラスの定義と、Goプログラムの設計におけるテクニックをご紹介します。 + +## 変数の定義 + +Go言語では変数は数多くの方法で定義されます。 + +`var`キーワードを使用することはGoの最も基本的な変数の定義方法です。C言語と異なり、Goでは変数の型を変数の後に置きます。 + + //"variableName"という名前で定義します。型は"type"です。 + var variableName type + +複数の変数を定義します。 + + //すべて"type"型の3つの変数を定義します。 + var vname1, vname2, vname3 type + +変数を定義し、初期化します。 + + //"variableName"の変数を"value"で初期化します。型は"type"です。 + var variableName type = value + +複数の変数を同時に初期化します。 + + /* + すべてが"type"型となる変数をそれぞれ定義し、個別に初期化を行います。 + vname1はv1,vname2はv2,vname3はv3 + */ + var vname1, vname2, vname3 type= v1, v2, v3 + +あなたは上述の定義が面倒だと思いますか?大丈夫、Go言語の設計者もわかっています。少し簡単に書くこともできます。直接型の宣言を無視することができるので、上のコードはこのようにも書けます: + + /* + 3つの変数を定義し、それぞれ個別に初期化する。 + vname1はv1,vname2はv2,vname3はv3 + このあとGoは代入される値の肩に従ってそれぞれ初期化を行います。 + */ + var vname1, vname2, vname3 = v1, v2, v3 + +これでもまだ面倒ですか?ええ、私もそう思います。更に簡単にしてみましょう。 + + /* + 3つの変数を定義し、それぞれ個別に初期化します。 + vname1はv1,vname2はv2,vname3はv3 + コンパイラは初期化する値に従って自動的にふさわしい型を導き出します。 + */ + vname1, vname2, vname3 := v1, v2, v3 + +これなら非常に簡潔になったでしょう?`:=`の記号は`var`と`type`に直接取って代わるものです。これらの形式を短縮宣言と呼びます。ただしこれにはひとつ制限があります。これらは関数の内部でしか使用できません。関数の外で使用するとコンパイルが通らなくなります。そのため、一般的には`var`方式でグローバル変数が定義されます。 + +`_`(アンダースコア)は特別な変数名です。どのような値もすべて捨てられてしまいます。この例では`35`という値を`b`に与えますが、同時に`34`は失われてしまいます。 + + _, b := 34, 35 + +Goはすでに宣言されている未使用の変数をコンパイル時にエラーとして出力します。例えば下のコードはエラーを一つ生成します。`i`は宣言されましたが使用されていません。 + + package main + + func main() { + var i int + } + +## 定数 + +いわゆる定数というのは、プログラムがコンパイルされる段階で値が決定されます。そのため、プログラムが実行される時には値の変更は許されません。定数には数値、bool値または文字列等の型を定義することができます。 + +この文法は以下の通りです: + + const constantName = value + //もし必要であれば、定数の型を明示することもできます: + const Pi float32 = 3.1415926 + +ここでは定数の宣言の例を示します: + + const Pi = 3.1415926 + const i = 10000 + const MaxThread = 10 + const prefix = "astaxie_" + +Go の定数は一般的なプログラミング言語と異なり、かなり多くの小数点以下の桁を指定することができます(たとえば200桁など)、 +float32に自動的な32bitへの短縮を指定したり、float64に自動的な64bitへの短縮を指定するには[リンク](http://golang.org/ref/spec#Constants)をご参照ください。 + +## ビルトイン基本型 + +### Boolean + +Goではbool値の型は`bool`です。値は`true`もしくは`false`です。デフォルト値は`false`です。 + + // コード例 + var isActive bool // グローバル変数の宣言 + var enabled, disabled = true, false // 型を省略した宣言 + func test() { + var available bool // 通常の宣言 + valid := false // 短縮宣言 + available = true // 代入操作 + } + + +### 数値型 + +整数型には符号付きと符号無しの2つがあります。Goはまた`int`と`uint`をサポートしています。この2つの型の長さは同じですが、実際の長さは異なるコンパイラによって決定されます。Goでは直接bit数を指定できる型もあります:`rune`, `int8`, `int16`, `int32`, `int64`と`byte`, `uint8`, `uint16`, `uint32`, `uint64`です。この中で`rune`は`int32`のエイリアスです。`byte`は`uint8`のエイリアスです。 + +>注意しなければならないのは、これらの型の変数間は相互に代入または操作を行うことができないということです。コンパイル時にコンパイラはエラーを発生させます。 +> +>下のコードはエラーが発生します。:invalid operation: a + b (mismatched types int8 and int32) +> +>> var a int8 + +>> var b int32 + +>> c:=a + b +> +>また、intの長さは32bitですが、intとint32もお互いに利用することはできません。 + +浮動小数点の型には`float32`と`float64`の二種類があります(`float`型はありません。)。デフォルトは`float64`です。 + +これで全てですか?No! Goは複素数もサポートしています。このデフォルト型は`complex128`(64bit実数+64bit虚数)です。もしもう少し小さいのが必要であれば、`complex64`(32bit実数+32bit虚数)もあります。複素数の形式は`RE + IMi`です。この中で`RE`が実数部分、`IM`が虚数部分になります。最後の`i`は虚数単位です。以下に複素数の使用例を示します: + + var c complex64 = 5+5i + //output: (5+5i) + fmt.Printf("Value is: %v", c) + + +### 文字列 + +前の章で述べた通り、Goの文字列はすべて`UTF-8`コードが採用されています。文字列は一対のダブルクォーテーション(`""`)またはバッククォート(`` ` `` `` ` ``)で括られることで定義されます。この型は`string`です。 + + //コード例 + var frenchHello string // 文字列変数の宣言の一般的な方法 + var emptyString string = "" // 文字列変数を一つ宣言し、空文字列で初期化する。 + func test() { + no, yes, maybe := "no", "yes", "maybe" // 短縮宣言、同時に複数の変数を宣言 + japaneseHello := "Konichiwa" // 同上 + frenchHello = "Bonjour" // 通常の代入 + } + +Goの文字列は変更することができません。例えば下のコードはコンパイル時にエラーが発生します。:cannot assign to s[0] + + var s string = "hello" + s[0] = 'c' + + +ただし、本当に変更したくなったらどうしましょうか?ここでは以下のコードで実現します: + + s := "hello" + c := []byte(s) // 文字列 s を []byte 型にキャスト + c[0] = 'c' + s2 := string(c) // もう一度 string 型にキャストし直す + fmt.Printf("%s\n", s2) + + +Goでは`+`演算子を使って文字列を連結することができます: + + s := "hello," + m := " world" + a := s + m + fmt.Printf("%s\n", a) + +文字列の修正もこのように書けます: + + s := "hello" + s = "c" + s[1:] // 文字列を変更することはできませんが、スライスは行えます。 + fmt.Printf("%s\n", s) + +もし複数行の文字列を宣言したくなったらどうしましょうか?この場合`` ` ``で宣言することができます: + + m := `hello + world` + +`` ` `` で括られた文字列はRaw文字列です。すなわち、文字列はコード内の形式がそのままプリント時の形式になります。文字列の変更はありません。改行はそのまま出力されます。例えばこの例では以下のように出力されます: + + hello + world + +### エラー型 +Goにはビルトインの`error`型があります。専らエラー情報の処理に使用されます。Goの`package`の中にはエラー処理を行う`errors`というパッケージがあります。 + + err := errors.New("emit macho dwarf: elf header corrupted") + if err != nil { + fmt.Print(err) + } + +### Goデータの低レイヤの保存 + +下の図は[Russ Cox Blog](http://research.swtch.com/)の中の一文で紹介されている[Goデータ構造](http://research.swtch.com/godata)の文章です。これらの基本型は低レイヤでメモリを分配し、対応する値を保存していることが見て取れるとおもいます。 + +![](images/2.2.basic.png?raw=true) + +図2.1 Goデータ形式の保存 + +## テクニック + +### グループ化による宣言 + +Go言語では、複数の定数・変数を宣言する場合、または複数のパッケージをインポートする場合、グループ化による方法で宣言することができます。 + +例えば以下のコード: + + import "fmt" + import "os" + + const i = 100 + const pi = 3.1415 + const prefix = "Go_" + + var i int + var pi float32 + var prefix string + +グループ化によって以下のような形式になります: + + import( + "fmt" + "os" + ) + + const( + i = 100 + pi = 3.1415 + prefix = "Go_" + ) + + var( + i int + pi float32 + prefix string + ) + +### iota列挙型 + +Goでは`iota`というキーワードがあります。このキーワードは`enum`を宣言する際に使用されます。このデフォルト値は0からはじまり、順次1が追加されます: + + const( + x = iota // x == 0 + y = iota // y == 1 + z = iota // z == 2 + w // 定数の宣言で値を省略した場合、デフォルト値は前の値と同じになります。ここではw = iotaと宣言していることと同じになりますので、w == 3となります。実は上のyとzでもこの"= iota"は省略することができます。 + ) + + const v = iota // constキーワードが出現する度に、iotaは置き直されます。ここではv == 0です。 + + const ( + e, f, g = iota, iota, iota //e=0,f=0,g=0 iotaの同一行は同じです + ) + +>他の値や`iota`に設定されているものを除いて、各`const`グループのはじめの定数はデフォルトで0となります。二番目以降の定数は前の定数の値がデフォルト値となります。もし前の定数の値が`iota`であれば、直後の値も`iota`になります。 + +### Goプログラムのデザインルール +Goがこのように簡潔なのは、それがいくつかのデフォルトの行為を持っているからです: +- 大文字で始まる変数はエクスポート可能です。つまり、他のパッケージから読むことができる、パブリックな変数だということです。対して小文字で始まる変数はエクスポートできません。これはプライベート変数です。 +- 大文字で始まる関数も同じです。`class`の中で`public`キーワードによってパブリック関数となっているのと同じです。対して小文字で始まる関数は`private`キーワードのプライベート関数です。 + +## array、slice、map + +### array +`array`は配列です。この定義は以下のようになります: + + var arr [n]type + +`[n]type`の中で、`n`は配列の長さを表しています。`type`は保存する要素の型を示しています。配列に対する操作は他の言語とよく似ていて、どれも`[]`を通して値の取得および代入を行います。 + + var arr [10]int // int型の配列を宣言します。 + arr[0] = 42 // 配列のインデックスは0からはじまります。 + arr[1] = 13 // 代入操作 + fmt.Printf("The first element is %d\n", arr[0]) // データを取得して、42を返します。 + fmt.Printf("The last element is %d\n", arr[9]) //値が代入されていない最後の要素を返します。デフォルトでは0が返ります。 + +長さも配列の一部ですので、`[3]int`と`[4]int`は異なる型になります。配列も長さを変えることはできません。配列間の代入は値渡しです。つまり、一つの配列が関数の引数となった場合、渡されるのは実はこの配列のコピーであり、ポインタではありません。もしポインタを使いたい場合は、この後にご紹介する`slice`型をご利用ください。 + +配列はもうひとつの`:=`で宣言することができます。 + + a := [3]int{1, 2, 3} // 長さが3のintの配列を宣言します。 + + b := [10]int{1, 2, 3} // 長さが10のint配列を宣言します。この中で3つの要素の初期値は1、2、3で、そのほかのデフォルトは0です。 + + c := [...]int{4, 5, 6} // 長さを`...`で省略することもできます。Goは自動で要素数から長さを計算します。 + +もしあなたが「配列に配列を込めたい場合は実現できますか?」と問うならば、当然ですとも、とお応えしましょう。Goはネストした配列をサポートしています。例えば下のコードでは二次元配列を宣言しています: + + // 二次元配列を一つ宣言します。この配列は2つの配列を要素としており、各配列には4つのint型の要素が含まれます。 + doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} + + // 上の宣言は簡略化できます。直接内部の型を省略しています。 + easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} + +配列の状態は以下のとおりです: + +![](images/2.2.array.png?raw=true) + +図2.2 多次元配列のマッピング関係 + + +### slice + +多くのアプリケーションでは、配列はあまりわたしたちの要求を満たしてはくれません。配列を初期化する場合、どれぐらいの大きさの配列が必要かわからないからです。そのため、"動的な配列"が必要となります。Goではこのようなデータ構造を`slice`と呼びます。 + +`slice`は本当の意味での動的な配列ではありません。これは単なる参照型です。`slice`は常に低レイヤの`array`を指しています。`slice`の宣言も`array`と同様に長さを指定する必要はありません。 + + // arrayの宣言と同じですが、長さは必要ありません。 + var fslice []int + +次に`slice`を宣言すると同時にデータを初期化します: + + slice := []byte {'a', 'b', 'c', 'd'} + +`slice`はひとつの配列またはすでに存在する`slice`の中から宣言することができます。`slice`は`array[i:j]`で取得することができます。この中で`i`は配列の開始位置です。`j`は終了位置です。ただし`array[j]`は含みません。長さは`j-i`となります。 + + // 10個の要素を宣言します。要素の型はbyteの配列です。 + var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + + // byteを含む2つのsliceを宣言します + var a, b []byte + + // aポインタ配列の3つ目の要素から始まり、5つ目の要素まで + a = ar[2:5] + //現在aの持つ要素は:ar[2]、ar[3]とar[4]です。 + + // bは配列arのもう一つのsliceです。 + b = ar[3:5] + // bの要素は:ar[3]とar[4]です。 + +>`slice`と配列は宣言時に区別されますのでご注意ください:配列を宣言するとき、中括弧の中で配列の長さを明示するかまたは`...`で自動的に長さを計算します。一方`slice`を宣言する時は、中括弧内には文字はありません。 + +これらのデータ構造は以下のようになっています。 + +![](images/2.2.slice.png?raw=true) + +図2.3 sliceとarrayの対応関係図 + +sliceには便利な操作があります + + - `slice`のデフォルト開始位置は0です。`ar[:n]`などは`ar[0:n]`と等価です。 + - `slice`の2つ目の値のデフォルトは配列の長さです。`ar[n:]`は`ar[n:len(ar)]`等価です。 + - もし配列の中から直接`slice`を取り出す場合は、`ar[:]`というような形で指定することができます。なぜならデフォルトのはじめの値は0で2つ目は配列の長さだからです。すなわち、`ar[0:len(ar)]`と等価となります。 + +ここではより多くの`slice`の操作についていくつか例を挙げます: + + // 配列を宣言 + var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + // sliceを2つ宣言 + var aSlice, bSlice []byte + + // 便利な操作のデモンストレーション + aSlice = array[:3] // aSlice = array[0:3] と同じ。aSliceには以下の要素が含まれます: a,b,c + aSlice = array[5:] // aSlice = array[5:10] と同じ。aSliceには以下の要素が含まれます: f,g,h,i,j + aSlice = array[:] // aSlice = array[0:10] と同じ。この場合aSliceにはすべての要素が含まれます。 + + // sliceからsliceを取り出す + aSlice = array[3:7] // aSliceには以下の要素が含まれます: d,e,f,g,len=4,cap=7 + bSlice = aSlice[1:3] // bSlice にはaSlice[1], aSlice[2] が含まれそれぞれの要素は以下のとおりです: e,f + bSlice = aSlice[:3] // bSlice には aSlice[0], aSlice[1], aSlice[2] が含まれます。それぞれ以下のとおりです: d,e,f + bSlice = aSlice[0:5] // sliceのsliceに対してcapの範囲内で拡張することができます。この時bSliceには以下の要素が含まれます:d,e,f,g,h + bSlice = aSlice[:] // bSliceにはaSliceのすべての要素が含まれます: d,e,f,g + +`slice`は参照型ですので、この中の要素の値を変更すると、そのほかのすべての参照でも値が変更されます。たとえば上の`aSlice`と`bSlice`で、`aSlice`の中の要素を変更すると、`bSlice`の対応する値も同時に変更されます。 + +概念上では、`slice`は構造体です。この構造体には3つの要素が含まれます:  +- 一つはポインタです。配列中の`slice`が示す開始位置を指しています。 +- 長さ、つまり`slice`の長さです。 +- 最大の長さ、`slice`の開始位置から配列の最後の位置までの長さです。 + + Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + Slice_a := Array_a[2:5] + +上のコードの正しい保存構造は下の図に示す通りです。 + +![](images/2.2.slice2.png?raw=true) + +図2.4 sliceに対応する配列の情報 + +`slice`に対しては、いくつかの便利なビルトイン関数があります: + +- `len` `slice`の長さを取得します。 +- `cap` `slice`の最大容量を取得します。 +- `append` は`slice`に対して一つまたは複数の要素を追加します。その後`slice`と同じ型の`slice`を返します。 +- `copy` 関数`copy`はもとの`slice`の`src`を`dst`に要素をコピーし、コピーした要素の個数を返します。 + +注:`append`関数は`slice`が参照した配列の内容を変更し得ます。そのため、参照先と同一の配列の他の`slice`にも影響します。 +しかし`slice`の中に余分なスペースが無い(`(cap-len) == 0`)場合、動的なメモリから新たな配列空間が割り当てられます。返される`slice`配列のポインタはこの空間を指しています。また、もとの配列の内容は変わりません。この配列を参照している他の`slice`は影響を受けません。 + +Go1.2より、sliceは三引数のsliceをサポートするようになりました。以前まで我々は以下のような方法でsliceまたはarrayからsliceを取り出していました + + var array [10]int + slice := array[2:4] + +この例ではsliceの要素数は8で、新しいバージョンでは以下のように要素数を指定することができます + + slice = array[2:4:7] + +上の要素数は`7-2`、即ち5となります。このように生成された新しいsliceでは最後の3つの要素にアクセスする方法がなくなります。 + +もしsliceが`array[:i:j]`のような形式だった場合は、第一引数は空と見なされ、デフォルトの0となります。 + +### map + +`map`の概念もPythonのディクショナリです。この形式は`map[keyType]valueType`です。 + +下のコードをご覧ください。`map`の読み込みと代入は`slice`と似ています。`key`を通して操作します。ただ、`slice`の`index`は`int`型のみになります。`map`には多くの型があります。`int`でもかまいませんし、`string`や`==`と`!=`演算子が定義されている全ての型でもかまいません。 + + // keyを文字列で宣言します。値はintとなるディクショナリです。この方法は使用される前にmakeで初期化される必要があります。 + var numbers map[string]int + // もうひとつのmapの宣言方法 + numbers := make(map[string]int) + numbers["one"] = 1 //代入 + numbers["ten"] = 10 //代入 + numbers["three"] = 3 + + fmt.Println("3つ目の数字は: ", numbers["three"]) // データの取得 + // "3つ目の数字は: 3"という風に出力されます。 + +この`map`は我々が普段目にする表と同じです。左の列に`key`、右の列に値があります。 + +mapを使う段階で注意しなければならないことがいくつかあります: +- `map`は順序がありません。毎回`map`の出力は違ったものになるかもしれません。`index`で値を取得することはできず、かならず`key`を使うことになります。 +- `map`の長さは固定ではありません。`slice`と同じで、参照型の一種です。 +- ビルトインの`len`関数を`map`に適用すると、`map`がもつ`key`の個数を返します。 +- `map`の値は簡単に修正することができます。`numbers["one"]=11`というようにkeyが`one`のディクショナリの値を`11`に変えることができます。 +- `map`は他の基本型と異なり、thread-safeではありません。複数のgo-routineを扱う際には必ずmutex lockメカニズムを使用する必要があります。 + +`map`の初期化では`key:val`の方法で初期値を与えることができます。また同時に`map`には標準で`key`が存在するか確認する方法が存在します。 + +`delete`で`map`の要素を削除します: + + // ディクショナリを初期化します。 + rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 } + // mapは2つの戻り値があります。2つ目の戻り値では、もしkeyが存在しなければ、okはfalseに、存在すればokはtrueになります。 + csharpRating, ok := rating["C#"] + if ok { + fmt.Println("C# is in the map and its rating is ", csharpRating) + } else { + fmt.Println("We have no rating associated with C# in the map") + } + + delete(rating, "C") // keyがCの要素を削除します。 + + +上述の通り、`map`は参照型の一種ですので、もし2つの`map`が同時に同じポインタを指している場合、一つの変更で、もう一つにも変更が行われます。 + + m := make(map[string]string) + m["Hello"] = "Bonjour" + m1 := m + m1["Hello"] = "Salut" // この時、m["hello"]の値もすでにSalutになっています。 + + +### make, new操作 + +`make`はビルトイン型(`map`、`slice`および`channel`)のメモリの割り当てです。`new`は各型のメモリを割り当てます。 + +ビルトイン関数`new`は本質的には他の言語で使われる同名の関数と機能が同じです:`new(T)`はゼロサプレスされた`T`型のメモリ空間を割り当て、そのアドレスを返します。すなわち`*T`型の値です。Goの専門用語で言えば、ポインタを返すということです。新たに割り当てられた型`T`のゼロ値です。とても重要なことに: + +>`new`はポインタを返します。 + +ビルトイン関数`make(T, args)`と`new(T)`は異なる機能を持っています。makeは`slice`、`map`または`channel`を作成し、初期値(非ゼロ値)を持つ`T`型を返すのみで、`*T`ではありません。本質的には、この3つの型が異なる点はデータ構造を指し示す参照が使用される前に初期化されているということです。例えば、データ(内部`array`)を指し示すポインタ、長さ,容量による3点で記述される`slice`の各項目が初期化される前は、`slice`は`nil`です。`slice`, `map`, `channel`にとって、makeは内部のデータ構造を初期化し、適当な値で埋め尽くされます。 + +>`make`は初期化後の(非ゼロの)値を返します。 + +以下の図は`new`と`make`の違いについて詳細に解説しています。 + +![](images/2.2.makenew.png?raw=true) + +図2.5 makeとnewの低レイヤでのメモリの割り当て + + +## ゼロ値 +"ゼロ値"というのは何も空の値ではありません。これは一種の"変数が埋めらる前"のデフォルト値であり、通常は0です。 +それぞれの型のゼロ値は以下の通りです + + int 0 + int8 0 + int32 0 + int64 0 + uint 0x0 + rune 0 //runeの実際の型は int32 です。 + byte 0x0 // byteの実際の型は uint8 です。 + float32 0 //長さは 4 byte + float64 0 //長さは 8 byte + bool false + string "" + +## links + * [目次]() + * 前へ: [こんにちは、Go](<02.1.md>) + * 次へ: [フローと関数](<02.3.md>) diff --git a/ja/05.1.md b/ja/05.1.md index 8122cccb..501133b3 100644 --- a/ja/05.1.md +++ b/ja/05.1.md @@ -36,7 +36,7 @@ mymysql、sqlite3のドライバではどのようにコールしているのか >新人はこの`_`にとても戸惑いがちです。実はこれはGoの絶妙な設計なのです。変数に値を代入する際、よくこの記号が現れます。これは変数を代入する時のプレースホルダの省略です。パッケージのインポートにこの記号を使っても同じような作用があります。ここで使用した`_`はインポートした後のパッケージ名で、このパッケージに定義されている関数、変数などのリソースを直接使用しない事を意味しています。 ->2.3節で述べたフローと関数の中でinit関数の初期化プロセスをご紹介しました。パッケージがインポートされる際はパッケージのinit関数が自動的にコールされ、このパッケージに対する初期化が完了します。そのため、上のデータベースドライバパッケージをインポートするとinit関数が自動的にコールされます。つぎに、init関数でこのデータベースドライバを登録し、以降のコードの中で直接このデータベースドライバを直接使用することができます。 +>2.3節のフローと関数の章においてinit関数の初期化プロセスをご紹介しました。パッケージがインポートされる際はパッケージのinit関数が自動的にコールされ、このパッケージに対する初期化が完了します。そのため、上のデータベースドライバパッケージをインポートするとinit関数が自動的にコールされます。つぎに、init関数でこのデータベースドライバを登録し、以降のコードの中で直接このデータベースドライバを直接使用することができます。 ## driver.Driver Driverはデータベースドライバのインターフェースです。methodがひとつ定義されています: Open(name string)、このメソッドはデータベースのConnインターフェースを一つ返します。