丸善出版の『プログラミング言語Go』の読書履歴です。

出てきた内容の気になったポイントのまとめや練習問題の解答(自分なりの)を記載していきます。
(ここに記載されている内容で問題が生じても責任は負えませんのであしからず…。)

練習問題は結構長くなるものが増えてきたので、本文記載のコードの修正の場合は修正部分だけ抜粋しています。
すべてのコードが見たい場合はGitHubにあるので、そちらを見てみてください。
プログラミング言語Go GitHub

とはいえ、練習問題に時間がかかりすぎて、なかなか先に進めない感じもあるので、飛ばしてしまっています。
すみません(;´Д`)
気が向いたら練習問題もやっていこうと思うので、その際は追記します。

さて、第6章はメソッドについてです。

もくじ

6.1 メソッド宣言
6.2 ポインタレシーバを持つメソッド
6.3 構造体埋め込みによる型の合成
6.4 メソッド値とメソッド式
6.5 例:ビットベクタ型
6.6 カプセル化

これまでの章のまとめはこちら

第1章 チュートリアル
第2章 プログラミング構造
第3章 基本データ型
第4章 コンポジット型
第5章 関数

6.1 メソッド宣言

メソッドと関数ってどう違うんだろう?と冒頭の説明を読んでもよくわからなかったり…(汗)
データ型に関連付けられた関数をメソッド、というらしいので、データ型に関数を定義する、というイメージでしょうか。

通常の関数とメソッドを宣言の仕方の違いは以下のようになります。

メソッドの宣言には追加のパラメータ p が書かれているのがわかります。この地下のパラメータのことをメソッドのレシーバと呼びます。

それぞれの呼び出し方は以下のようになります。

このようにメソッドは型に紐付いた形の関数になります。

6.2 ポインタレシーバを持つメソッド

関数の引数値はコピーが渡されます。関数が変数を更新したい場合などはポインタを使って変数のアドレスを渡す必要があります。
メソッドも同様のことが言えて、レシーバ変数を更新する必要がある場合は、ポインタを使うことができます。

6.3 構造体埋め込みによる型の合成

前節で紹介した Point 構造体を持つ ColoredPoint 構造体を定義します。

こうすることによって、ColoredPoint は Point のメソッドを使うことができるようになります。

p.Distance(q.Point) としたときに、まずColoredPoint構造体に Distanceメソッドがないか調べます。
なければ、Point構造体のメソッドを調べる、と言った流れになります。

ここまで来て、メソッドって他の言語のクラスっぽいなぁ、と思いました。
構造体の埋め込みって継承っぽいですよね。

GOはクラス自体はないけれど、構造体とメソッド、それからこのあとに出てくるインターフェースでオブジェクト指向を実装しているようです。

6.4 メソッド値とメソッド式

今まで見てきたメソッドは p.Distance() と言った書き方をしていましたが、p.Distance とするとメソッド値を生成することができます。
メソッド値とは特定のレシーバ値にメソッドを結びつけている関数で、変数に代入することができます。

メソッド値と関係しているものでメソッド式というものもあります。
メソッドを呼び出すときには通常はレシーバーを使いますが(p.Distance(q) のような呼び出し方)、メソッド式の場合はデータ型.メソッドというように書き、レシーバの代わりに普通の第一引数を持つ関数値を生成します。

6.5 例:ビットベクタ型

ビットベクタの操作方法などをメソッドを使って説明しています。
ここはサンプルソースを見てもらえばいいと思うので説明は省きます。

6.6 カプセル化

オブジェクトの変数やメソッドはクライアントからアクセス出来ないようになっていればカプセル化されているといいます。
カプセル化は情報隠蔽とも呼ばれます。

Goでは名前の可視化を制御する仕組みはひとつしかありません。
大文字で始まる識別子は、それが定義されたパッケージ外へ公開され、大文字で始まっていない識別子は公開されません。
他の言語によくある、public や private といったキーワードはGOにはないということですね。

同じ仕組みで構造体のフィールドやメソッドへのアクセスを制限するので、オブジェクトをカプセル化するためには、オブジェクトを構造体にする必要があります。

カプセル化の単位はパッケージであり、他の言語によくある型ではない、というのが特徴的だなと思います。
構造体のフィールドは同じパッケージ内であればアクセス可能になります。

この節ではカプセル化の利点などの説明もされています。

といったところで、メソッドの章は完了です!
ここまでやってようやくGo言語でのオブジェクト指向プログラミングの手法がわかってきましたね。

次章はインタフェースです。がんばろう。

丸善出版の『プログラミング言語Go』の読書履歴です。

出てきた内容の気になったポイントのまとめや練習問題の解答(自分なりの)を記載していきます。
(ここに記載されている内容で問題が生じても責任は負えませんのであしからず…。)

練習問題は結構長くなるものが増えてきたので、本文記載のコードの修正の場合は修正部分だけ抜粋しています。
すべてのコードが見たい場合はGitHubにあるので、そちらを見てみてください。
プログラミング言語Go GitHub

とはいえ、練習問題に時間がかかりすぎて、なかなか先に進めない感じもあるので、飛ばしてしまっています。
すみません(;´Д`)
気が向いたら練習問題もやっていこうと思うので、その際は追記します。

さて、第5章は関数についてです。

もくじ

5.1 関数宣言
5.2 再帰
5.3 複数戻り値
5.4 エラー
5.5 関数値
5.6 無名関数
5.7 可変個引数関数
5.8 遅延関数呼び出し
5.9 パニック
5.10 リカバー

これまでの章のまとめはこちら

第1章 チュートリアル
第2章 プログラミング構造
第3章 基本データ型
第4章 コンポジット型

5.1 関数宣言

関数の宣言は以下のような構文になります。

parameter-listは引数で、名前を型を指定します。
result-list は戻り値の型を指定します。

なので、具体的に書いてみると、以下のようになります。

Go言語には引数のデフォルト値や名前付き引数、というのもないのですね。

5.2 再帰

Goでは関数を再帰的に使うことができます。
自分自身を直接的にも間接的にも呼び出すことができます。
4.4節のサンプルですでに使っているのですが、さらに詳細な説明がされています。

ここの節では golang.org/x/net/html パッケージを使うので、 go get を使ってインストールしておきましょう。

使い方、と言ったほどのことはなくて、普通に自分自身を呼び出してあげればOKです。

具体的な使い方はGitHub のサンプルコードを見ていただいて…。

5.3 複数戻り値

今までも出てきていましたが、関数は複数の戻り値を返すことができます。
戻り値の型を指定するところで (データ型, データ型) と複数カンマ区切りで書いてあげます。
もちろんそれぞれ違う型でも大丈夫です。

5.4 エラー

Go言語の場合、他の言語によくある例外を使ってエラー処理をするのでなく、戻り値で error を一緒に返すというような方法と取っているようです。
いままでのサンプルコードでも error を受け取るコードは出てきていましたね。

error は nil か nil でないかであり、nil の場合は成功を、nil でなければ失敗を意味します。
nil 出ない場合の error は fmt.Println(err) などとすると、エラーメッセージを表示してくれます。

5.5 関数値

関数はファーストクラス値なので、関数は他の値と同様に型を持ち、変数に代入したり、関数に渡したり、関数から返したりすることができます。

以下のように3つの関数があったとして、変数 f に関数である square を代入して、f として実行することが可能です。
square と negative は引数と戻り値の数、型が同じなので、同じデータ型とみなされるので、そのまま f に negative を代入することはできます。
product は引数の数が違うので違う型になるので、f に代入することはできません。

5.6 無名関数

関数値を表す関数リテラルは全ての式内で使うことができ、関数リテラルは関数宣言のようにかきますが、func の後に名前がありません。こういった関数を無名関数と呼びます。

例えば、strings.Map の第一引数を無名関数で書くと次のようになります。

このように無名関数は引数に渡すこともできますし、次のように戻り値として返すこともできます。

5.7 可変個引数関数

可変個引数関数とは可変個の引数で呼び出すことができる関数です。
いままでにも使っている fmt.Printf などがこれにあたります。

可変個引数関数を宣言するには、パラメータの型の前に ... を付けます。

この sum 関数を呼び出すときは、0個以上の引数を指定すればいいので、以下のように書きます。

また、スライスを渡すこともできて、その場合は次のように書きます。

5.8 遅延関数呼び出し

普通の関数やメソッドの呼び出しの前に defer を付けると、遅延関数呼び出しとなります。
遅延関数呼び出しを行うと、関数と引数の式は defer文が実行されるときに評価されますが、実際の呼び出しは defer 文を含む関数が完了されるまで遅延されます。

5.9 パニック

Goの型システムはコンパイル時に多くの誤りを検出しますが、それ以外の境界外への配列アクセス、nilポインタ参照などの誤りは実行時の検査が必要になります。
Goランタイムがそのような誤りを検出した際にパニックとなります。

パニックは通常の実行を停止し、ログメッセージを表示してクラッシュします。

パニックを発生される場合は panic("error message") とすればいいようです。

5.10 リカバー

パニックは通常プログラムを終了してしまいますが、パニックから回復したときもあります。
そのときに使えるのがリカバーです。

遅延された関数内で recover 関数が呼び出され、かつ defer 文を含む関数がパニックになると、recover はパニックを終了させてパニック値を返します。

と、ここまでで関数については終了です。

ちょっと私自身理解不足なところが多いので、時間があるときにでも見直せたらな、と思います。

ひとまず、先に進むことにします!

Go言語の環境はこんな感じでした。

macOS : Sierra(10.12.1)
Golang : 1.6.3

普通に動作していたし、コンパイルもできていました。

諸々あって、Sierra(10.12.2) にアップデートしたんですね。
そうしたら、Goがコンパイルできなくなってしまい。。。

Google先生に相談したら Sierra からは Go は 1.7 以降しか対応しないらしいという事実が判明。
なんで今まで使えていたんだろうという疑問は残りつつ…。

結論から言えば、1.7にアップデートすれば解決します。

というわけでやってみた作業。HomebrewでGoを入れていたはずなので、とりあえず upgrade すればいいんだろう、思ったら

なにやらいろいろ怒られた。
ふむ。。。

インストール可能なGoのバージョンを調べてみたら、1.6.3が最新になっている。

あぁ、homebrew のアップデートが必要なのか。

無事アップデートが終わったところで、もう一度確認。
1.7.4発見!

なので再び upgrade してみる。

だーっと色々出て、うまく行ったようなので、バージョンチェック

1.7.4 になったー

これでするっとコンパイルもできるようなりました!よかった!

とは言え、私は仕事で使っているわけでないので、Goのバージョンアップするのは問題なかったのですが、
お仕事で Go の 1.6.3 を使っている人は Sierra にしてはいけないってことのようです…。

macOSのバージョンアップは色々起きるなぁ。。。

丸善出版の『プログラミング言語Go』の読書履歴です。

出てきた内容の気になったポイントのまとめや練習問題の解答(自分なりの)を記載していきます。
(ここに記載されている内容で問題が生じても責任は負えませんのであしからず…。)

練習問題は結構長くなるものが増えてきたので、本文記載のコードの修正の場合は修正部分だけ抜粋しています。
すべてのコードが見たい場合はGitHubにあるので、そちらを見てみてください。
プログラミング言語Go GitHub

さて、第4章はコンポジット型についてです。

もくじ

4.1 配列
4.2 スライス
4.3 マップ
4.4 構造体
4.5 JSON
4.6 テキストテンプレートとHTMLテンプレート

これまでの章のまとめはこちら

第1章 チュートリアル
第2章 プログラミング構造
第3章 基本データ型

4.1 配列

配列は特定の型の0個以上の固定長列です。
配列は固定長なので、可変長なスライスを使うことのほうが多いですが、基本として押させておくといいと思います。

配列の宣言は次のように書きます。
[] が先にくるのでちょっと見慣れないですが、C/C++やJavaと同じような書き方ですね。

配列の通常の変数と同様に宣言時に初期化されます。
この例の場合は int型の配列なので、3つの要素は 0 で初期化されます。

各要素にアクセスするには次のように書きます。
インデックスは0から始まるので、3つの要素を持つ配列の場合は 0〜2を指定します。

配列のインデックスを要素を表示する場合は次のように range を使ってforでループしてあげればOKです。
インデックスか要素かどちらか一方が必要な場合は、不要な方を _ を指定してあげます。

宣言時に任意の値で初期化したい場合は次のように書きます。
また、初期化に値の数は指定した要素数より少なくても大丈夫で、その場合は 0 で初期化されます。

どちらも3つ目の要素を表示しようとしているので、3 と 0 が表示されるはずです。

初期値を指定する場合は、データ型の指定を省略できます。

さらに要素数を省略することもできて、[...] としてあげます。ただし、この場合は初期化で指定された要素数になることに注意しましょう。」

要素数は配列の型の一部なので、[3]int[4]int は違う型とみなされます。
なので、 [3]int で宣言した変数に対して、[3]int{} という形でまとめて代入することは可能ですが、[4]int{} という形で代入することはできません。

練習問題4.1

あーもう、かなり強引なやり方なので違うと思います…
アルゴリズムがわからん…。

練習問題4.2

こちらはまぁ、今までもよく出てきているコマンドラインフラグと標準入力を使ったものですね。

4.2 スライス

スライスはすべての要素が同じ型である可変長配列です。
大きさがない配列のようなもので、宣言は以下のように書きます。

使い方は配列とにていますが、スライスは比較ができないので2つのスライスが同じ要素で構成されているか調べるのに == が使えません。
バイトスライスである []byte の場合は標準で比較するためのbytes.Equalを提供されていますが、その他の型のスライスの場合は自分で比較を行う必要があります。

4.2.1 append関数

標準で用意されているappend関数を使ってスライスに項目を追加することができます。
使い方は以下のようになります。

追加したい値はカンマで区切って複数個指定することも可能です。
append()をしただけでは引数に指定したスライスは更新されないので、必ず変数に代入して上げる必要があります。

4.2.2 スライス内での技法

ここではさらに要素の修正を行う例の説明があります。
まぁここは書籍を読んでいただくことにして、さて、練習問題へ…

練習問題 4.3

スライスの代わりに配列へのポインタを使うようにreverseを書き直す、というものでして、だいぶ力技な気がするのでどうでしょうね…

練習問題 4.4

rotateを作りなさい、という問題なのですが、やっぱりゴリ押し感が…。

4.3 マップ

マップ型は map[K]V と書きます。ここでの K はキーの型で、V は値の型になります。
マップ内のすべてのキーの型は同じであり、すべての値の型は同じである必要がありますが、キーと値は同じ型である必要はありません。

map を作るには標準で用意されている make 関数を使います。

マップの作成と同時に初期値を入れることも可能で、その場合はmake関数を使わずに書くことができます。

map の要素にアクセスするときはキーを使えばいいので、このように書きます。

map に要素を追加するときは新しいキーを使って値を代入すればOKです。

map から要素を削除するときは delete関数を使います。

map の全てのキーと値を列挙するには for と range を使います。

練習問題 4.8, 4.9

すみません、マップの練習問題は飛ばします…。

4.4 構造体

構造体は合成データ型であり、0個以上の任意の型の変数をまとめて管理するものです。
それぞれの変数をフィールドと呼ばれます。

構造体の定義は type 構造体名 struct {...} となります。

それぞれのフィールドにアクセスするには、構造体名.フィールド名 という形になります。

4.4.1 構造体リテラル

宣言時に初期化を行うこともできます。

ただしこの場合は全てのフィールドに対して、正しい順序で値を指定する必要があるので、image.Point{x, y}やcolor.RGBA{red, green, blue, alpha}などのようにフィールドの順番が明らかで小さい構造体で使われることが多いです。

もうひとつ初期化の方法があり、下記のようにフィールド名を指定して値を代入する方法です。

こちらの場合は全てのフィールドを指定する必要はなく、必要なものだけ初期化できます。
初期化されていないものはゼロ値が設定されます。
フィールドの順序も気にする必要はありません。

4.4.2 構造体の比較

構造体のすべてのフィールドが比較可能なものであれば、構造体自体の比較も可能です。
その場合は ==!= が使えます。

4.4.3 構造体埋め込みと無名フィールド

構造体の中に別の構造体を使いたいということはよくあると思いますし、そういった使い方ももちろんできます。

このように宣言した場合、CircleからPointのXやYにアクセスするには以下のように書くことになり、ちょっと面倒です。

そこで、型は持つけれど名前を持たないフィールドを宣言することができて、そういったものを無名フィールドと呼びます。
その場合は以下のように宣言します。

この場合、PointのX、Yにアクセスするには以下のようにすればよいので、あたかもCircle自体にフィールドが宣言されているかのように使うことができます。

無名フィールドを使って宣言していても、きちんと構造体名を指定して c.Point.X = 8 というように指定することも可能です。

ただし、初期化を行うときには無名フィールドを使うことはできないので、以下の2つの方法で初期化してください。

4.5 JSON

Go言語は encoding/json パッケージがあります。
json.Marshaljson.MarshalIndent を使うと Go のデータ構造をJSONへ変換してくれます。

構造体を使ってJSONのデータ構造を作っておきます。
json:"released" の部分ですが、これはJSONオブジェクトを作るときにフィールドを名をYear ではなく released にする、という意味になります。

構造体ができたら、データを以下のように作っておきます。

このデータをJSONオブジェクトに変換するには以下のようにします。

Marshalでもいいのですが、MarshalIndentにしておくと、フィールドごとにインデントされた状態で出力してくれるので見やすくなります。

これを実行すると、以下のように出力されます。

練習問題4.10 〜 4.13

すみません。ちょっと練習問題はお休みします。

4.6 テキストテンプレートとHTMLテンプレート

テキストテンプレートやHTMLテンプレートは text/template や html/template パッケージを使えます。

テンプレートとは、アクションと呼ばれる二重波括弧{{...}} で囲まれた部分を1ヵ所以上含んでいる文字列またはファイルです。

{{}} のなかには構造体のフィールドを指定すれば、その値が表示されるようになります。

簡単なサンプルですが、このようになります。

まずテンプレートとなる文字列(templ)を作っておいて、templを元にテンプレートを生成します。
テンプレートに入れ込むための構造体を作って、フィールドを初期化します。
生成したテンプレートを Execute を使って出力します。

上のサンプルはテキストテンプレートの使い方ですが、HTMLテンプレートも基本的には同じように使うことができます。

その他のサンプルが見たい場合はGitHub にソースを参照してください。

さて、、、途中ちょっと他の勉強をしていたりで、だいぶ時間がかかってしまいましたが、ようやくコンポジット型を読了。
次は5章関数です。早めに終わらせたい…。

丸善出版の『プログラミング言語Go』の読書履歴です。

出てきた内容の気になったポイントのまとめや練習問題の解答(自分なりの)を記載していきます。
(ここに記載されている内容で問題が生じても責任は負えませんのであしからず…。)

練習問題は結構長くなるものが増えてきたので、本文記載のコードの修正の場合は修正部分だけ抜粋しています。
すべてのコードが見たい場合はGitHubにあるので、そちらを見てみてください。
プログラミング言語Go GitHub

さて、第3章は基本データ型についてです。

もくじ

3.1 整数
3.2 浮動小数
3.3 複素数
3.4 ブーリアン
3.5 文字列
3.6 定数

これまでの章のまとめはこちら

第1章 チュートリアル
第2章プログラミング構造

3.1 整数

Go言語の整数型には符号付きと符号なしがあります。
符号付き整数型は int8型、int16型、int32型、int64型があり、符号なし整数型には uint8型、uint16型、uint32型、uint64型があります。

また、ビット数が32ビットか64ビットになる int型と uint型もあります。
これらのビット数はハードウェア依存です。

他に rune型というのがあって、int32のシノニムで、慣習的にUncodeのコードポイントとして使われます。
byte型というのもあって、これはuint8のシノニムで、生データを扱うときに使われるようです。
それから、uintptr型というのもあって、これはポインタを格納するときに使うようです。

通常はint、uintを使えば良いようです。
ただ、intとint32と言ったデータ型は暗黙的に変換してくれないので、int32(x) といったように明示的に変換する必要があります。

算術、論理、比較演算子は次のようなものがあり、CやJavaなどと同じですね。
*, /, %, +, -, <<, >>, &, &^, |, ^, ==, !=, <, <=, >, >=, &&, ||

3.2 浮動小数点

Goでは float32 と float64 があって、それぞれ精度が6桁と約15桁になります。

小数点より前の桁を省略(.707)、もしくは後の桁を省略(1.)することができます。

非常に小さな値や大きな値は e または E を使った科学的記数法で書くこともできます。

練習問題3.1

不正な値があったらポリゴンをスキップする、という問題なので、単純にIsNaN() で値を調べるif文を追加しています。
(文中にあるソースコードの修正なので、修正部分の関数だけ抜粋します)

練習問題3.2

mathパッケージの別の関数を使って違う図形を作りなさい、という課題なのですが、数学が苦手ゆえ解答が出ず。。。
悩みすぎて先に進めなさそうなので、時々考えることにしてちょっとパスします(汗)

練習問題3.3

高さに基づいて色を変えよ、ということなのですが、こちらもイマイチ解答が浮かばずでして。。。
色はstyleを設定することで変更可能です。

練習問題3.4

SVGデータをクライアントに書き出すWebサーバを作成する、という問題なので、1章で作ったWebサーバを参考にしてこんな感じにすればブラウザで図形を見れるようになります。

HTTPリクエストでパラメータを受け取って高さなどを指定できるように、ともなるのですが、この辺は練習1.12でもやっているのでそちらを参考にしてください。

3.3 複素数

複素数ってなによ、と思うのは私だけ?(汗)

数学における複素数(ふくそすう、英: complex number)は、実数の対 a, b と 1 と線型独立な(実数ではない)要素 i の線型結合 a + bi の形に表される数(二元数: 実数体上の二次拡大環の元)で、基底元 i はその平方が −1 になるという特別な性質を持ち虚数単位と呼ばれる。

wikipediaより

全然わかんない…(@_@;)

ま、ま、ま、とりあえず読み進めます。はい。

複素数の生成にはcomplex関数が使えて、次のように書きます。

もっと単純に書くこともできて、次のようになります。

real関数、imag関数で実部と虚部を取り出すことができます。

練習問題3.5〜3.8

えぇと、、、数学が苦手な私にはだいぶ難しく、ちょっと解けていません。。。
ここで時間使いすぎても先に進めないので、この説の練習問題は飛ばしてしまいました。すみませんm(_ _)m

練習問題3.9

この問題は画像データをクライアントに書き出すWebサーバを作る、というものなので、問題1.12を参考にすれば出来ると思います。
パラメータを取得するところは作りこんでいませんが、クライアントに書き出すところまで作ったものがGitHubにアップロードしてあるので参考にしてみてください。
GitHub – 練習問題3.9

3.4 ブーリアン

ブーリアンは bool 型を使います。取り得る値は true と false の2つだけです。

&&演算子と || 演算子と組み合わせる事ができて、次のように書くことも可能です。

こうすると出力結果は false になります。
s が空文字の場合は s[0] でエラーになってしまうので、あらかじめ s != "" で空文字かどうかのチェックをしてから、1文字目のチェックをしているわけですね。
空文字の場合は最初の条件の時点でfalseになるので、エラーにならず処理はきちんと終わります。

それから、int と boolは暗黙の変換はないので、ifを使って変換することになります。

こんな感じに変換関数を用意しておくといいかもね、というお話でした。

3.5 文字列

テキスト文字列はUTF-8エンコードされたのUnicodeです。

文字数は組み込み関数の len() を使って取得でき、 s[0] とすると0番目の文字を取り出すこともできます。
部分文字列も取り出せて、 s[0:5] と言ったように書けばOKです。この場合、0から5未満の文字列を取り出すことになります。

+ 演算子を使って文字列を結合して新しい文字列を生成することができます。

あくまでも新しい文字列が生成されるので、s を代入しておいた t は元のままの文字列になります。

文字列は不変なので、文字列のデータを直接変換することはできません。
例えば以下のようにするとコンパイルエラーになります。

3.5.1 文字列リテラル

文字列リテラルは ""(ダブルクォート)で囲んで書きます。

\(バックスラッシュ)で始まるエスケープシーケンスも使えます。

生文字列リテラル(raw string literal)はダブルクオートの代わりにバッククォート ` で囲みます。
生文字列リテラルはエスケープシーケンスが使えません。
ま文字列はプログラムソース内で複数行に広げることができたり、バックスラッシュを含むことが多い正規表現を書くときに便利です。

3.5.2 Unicode

昔はASCIIだったけど、いろいろな言語に対応するためにUnicodeができたよ、といった話です。

Go言語でも文字列はUnicodeで扱われます。
文字コードはGo言語ではルーン(rune)と呼ばれる規格番号を割り当てています。

3.5.3 UTF-8

UTF-8はUnicodeコードポイントのバイトしての可変長エンコーディングです。
最近はUTF-8が使われることが非常に多いですね。

Go言語ではutf-8パッケージが用意されていて、いろいろな機能があるようです。
ルーンとUTF-8の変換と言った関数も用意されています。

3.5.4 文字列とバイトスライス

文字列を操作するには、bytes、strings、strconv、unicode の標準パッケージを使うことができます。

strings パッケージは文字列の検索、置換、比較、トリミング、分割、連結などの関数を提供しています。
bytes パッケージは文字列をバイトスライスとして操作することができて、stringsと同じような機能も持っています。
strconv パッケージは整数値、ブール値、浮動小数点値から文字列へ変換やその逆変換などの機能を提供します。
unicode パッケージはルーンを分類するための関数などを提供します。

この節ではこれらのパッケージを使わないで文字列をバイトスライスとして扱う方法や、stringsやbytesを使った方法などを紹介しています。

この節では練習問題があるので、文中に出てくる commma プログラムから修正した部分だけ抜粋しています。

練習問題 3.10

文字列連結の代わりに bytes.Buffer を使って行う、というものです。ちょっと冗長な気もしますがとりあえず…。

練習問題3.10 GitHub

練習問題 3.11

comma を機能拡張して、符号記号を持つ浮動小数点を扱えるようにする、という問題です。

練習問題3.11 GitHub

練習問題 3.12

この問題はちょっと飛ばしてしまいました。すみません…m(_ _)m

3.5.5 文字列と数値の変換

文字列と数値の変換はよくやるのですが、Go言語の場合は strconv パッケージか fmt.Sprintf を使うと簡単にできます。

3.6 定数

定数は実行時ではなくコンパイル時に評価が行われることが保障されている式です。
定数にはブーリアン、文字列、数値の基本型を使うことが可能です。

定数を定義するには const を使います。

定数もひとつの宣言内に書くことができます。

3.6.1 定数生成器 iota

const宣言で定数生成器 iota を使うことができます。

次のように書くと、Sundayはint型なので 0 が設定されます。
そのあとのMonday以降の定数には値を指定していませんが、1ずつインクリメントされた値が設定されます。

多言語によくある Enumのような型にすることができます。

練習問題 3.13

iotaはビット演算はできますが、塁上演算子がないので、1000の累乗を生成するにはどうしたらいいか、という問題です。
単純に1000を掛けて行くようにしただけですが、これでいいのかしら…

3.6.2 型付けなし定数

const宣言では型に結びついていない定数を定義することができて、その場合は基本型の値より遥かに高い数値精度を表現することができます。

前節で Zib や YiB は定数にそのまま代入しようとしたり、fmt.Printlnで表示しようとするとオーバーフローを起こしてエラーになっていましたが、次のように式に使うことが可能です。

また変数や定数に代入するときには明示的な変換を必要しません。
ただし、変数に代入したあとに精度の違う変数に使いたい場合は型変換が必要となります。

さて、、、ようやく基本データ型の章が終わりました。
この投稿も結構なボリュームになりましたが、書籍もかなりボリュームがあります。
もちろん基本中の基本な章なのでしっかり抑えておくことが大事だと思います。

丸善出版の『プログラミング言語Go』の読書履歴です。

出てきた内容の気になったポイントのまとめや練習問題の解答(自分なりの)を記載していきます。
(ここに記載されている内容で問題が生じても責任は負えませんのであしからず…。)

この章では主に変数やパッケージ、スコープについての説明になります。

練習問題があまりないので、各節の気になったポイントを書いていこうと思います。

もくじ

2.1 名前
2.2 宣言
2.3 変数
2.4 代入
2.5 型宣言
2.6 パッケージとファイル
2.7 スコープ

2.1 名前

Go言語では大文字小文字は区別されるので、heapSort と Heapsort は異なる名前になります。
(大抵の言語はそうですけど。)

最初の文字が大文字が小文字かでパッケージ外から見えるかどうかが変わって、大文字だとパッケージ外からアクセス可能になります。

他の言語だと関数名の先頭は小文字っていうのが多いので fmt.Println() とか大文字で始まるのが気持ち悪いなぁと思っていたのですが、なるほどこういうことなのですね。

なので他言語でよく見られる public や private と言ったキーワードがないようです。

関数内で宣言されたローカルなので関数内でしか使えませんが、関数外で宣言された変数はそのパッケージ内からは使うことができます。

2.2 宣言

宣言において重要なものが4種類あって、それは var、const、type、funcで、それぞれ変数、定数、型、関数ですね。

2.3 変数

変数はvarを使って定義して、初期値を設定します。基本構文は以下になります。

具体的に書くこんな感じ。

type か expression の部分を省略することができます。
type が省略されたときは、初期値によって型が決まります。(型推論ですね)
expression が省略された場合はその方に対するゼロ値になります。
数値なら0、真偽値ならfalse、文字列なら””、インタフェースと参照型はnilと言った具合です。

単一宣言で複数の変数を宣言することができて、初期値を宣言時に設定する場合はデータ型が異なっていてもOKです。

2.3.1 省略変数宣言

ローカル変数を宣言して初期化するときに省略変数宣言を使うことができます。

チュートリアルで sep := " " とか出てきてなんだろうと思っていたのですが、ようやく納得ですw

宣言時に初期値を設定しない場合や明示的な型の宣言が必要な場合は var を使います。

諸略変数宣言ですが、複数の変数でもOKで、同じように := を使います。

便利だからと言って多用し過ぎると可読性が落ちてしまうので、ローカル内でそれほど使われないというような変数のみにしたほうがよさそうですね。

2.3.2 ポインタ

おぉ。ポインタ。C/C++以外ではポインタって用語を使う言語が少ないので、ちょっと身構えてしまいますね。
(もともとC/C++プログラマなんですけど、私w)

C/C++のポインタとほぼ同じような考え方です。
ポインタを指す場合は & を使って、ポインタの中身を取り出すときは * を使います。

このようなソースの場合は p は x のポインタ(変数のアドレス)が格納されているので、*p とするとポインタの中身を書き換えるので、x も書き換わります。

うん、C/C++と同じですね。

2.3.3 new関数

変数を作成する別の方法として new 関数があります。

変数名を付ける必要がないときなどに便利そうです。

すごく単純な例ですけど、こういう使い方ができるようです。

2.3.4 変数の保存期間

変数は到達不可能になるまで存在し続け、その後はそのメモリ領域は再利用されるかもしれない、というお話ですね。

ただ、ガベージコレクションが基本的にやってくれるので、そこまで神経質に考える必要はないけれど少し頭に入れておくのはいいとは思います。

2.4 代入

代入するには = を使えばOKです。これまでにも出てきていますが。

+=*=などや++--も使えます。

2.4.1 タプル代入

タプル代入では複数の変数に一度に代入ができます。

以下のような2つの変数の値を交換するという使い方もできます。

今までにも出てきたような関数から複数の値を受け取るようなものもタプル代入ですね。

Go言語は使われない変数を定義することができないので、複数値を返す関数の1つの値しか使わない、という場合には ブランク識別子 _ (アンダースコア) を指定することで安全に破棄してくれるようになります。

例えば、io.Copy() はコピーしたバイト数とエラー値を返しますが、バイト数がいらない場合はブランクにしてあげればOKです。

2.4.2 代入可能性

暗黙的に発生する代入があり、例えば、関数は引数をパラメータ変数に暗黙的に代入するというようなお話ですね。

あとはスライスの初期値の設定なんかもそういうことらしいです。

型によっても変わってくるので、あとの章で説明があるようです。

2.5 型宣言

もともと用意されている型はいろいろありますが、type宣言をすると既存の方と同じ基底型を持つ新しい型を作ることができます。

構文はこのようになります

たとえば、長さの単位毎に型を作って見るとすると以下のようになります。

どちらもflota64を基底型としていますが、まったく別の型として使うことができます。

typeも名前の先頭を大文字で書くとパッケージ外からも使うことができるようになります。

2.6 パッケージとファイル

今までもなんとなく書いてきたpackageについてです。

他の言語と同じように名前空間として機能があって、同じ関数名がバッティングしないようにするために使います。

構文は次のようになります。

同じパッケージに属しているファイルであれば、パッケージ名を使うことなく関数や変数を使うことができます。

練習問題2.1

さて、この章では初めても練習問題です。

書籍の本文に記載されている摂氏、華氏の変換モジュールに絶対温度との変換も追加しなさい、というようなものですね。

とりあえずこんな感じでいいかな、と…
exportedな関数にドックコメントをつけていないとwarningが出てしまいますが、とりあえず面倒なので入れていません(汗)

2.6.1 インポート

パッケージを作ったら、使う場合はインポートをしてあげなければいけません。

今までも fmtやstringsなどなどいろいろとインポートしていたのも同様ですね。

パッケージ名とフォルダ名は一致させておいたほうがいいようです。
なぜならば、インポートで指定するのはフォルダ名なんですよね。

というわけで、私はGOPATHで指定したパスのsrcフォルダのなかに、lessons というフォルダを作っていその中に書籍のソースや練習問題を入れています。
なので、前節のソースコードは $GOPATH/lessons/ch2/tempconv というフォルダに入れてあります。

このtempconvをインポートする場合は下記のように指定してあげればOKです。
$GOPATH/src 以下のパスを指定しないと、標準パッケージを見に行こうとするので、独自パッケージの場合はパスの指定が必要なようです。

こうすると、標準パッケージと同じように tempconv.FToC というように書けるわけです。

練習問題2.2

さてさて、練習問題ですね。
main.goでコマンドライン引数がない場合は、オプションと値を入力してもらうようにしています。
それから、コマンドライン引数の場合は flag を使ってオプションと値を取るようにしました。

2.6.2 パッケージ初期化

パッケージの初期化処理は func init() {...} という特殊な関数を使うことができます。

変数の初期化程度なら、パッケージレベルで行えばいいのですが、処理が複雑になってくるとそれも難しいので、そういうときに init() を使うといいようです。
他の言語のクラスのコンストラクタのようなものですね。最初に必ず実行されます。

練習問題2.3

単一式ではなくループってことなので、こんなかんじ?
性能比較はやっていません…。

練習問題2.4

ビットシフトしながらということなので、こんな感じでしょうか…。
PopCount()のみ書き出しています。他の部分は練習問題2.3と同じです。

練習問題2.5

x&(x-1) は最下位ビットをクリアする、という事実を使ってビット数を求める、ということで自身が無いですが、こんな感じで…
とりあえずは動いてます。

2.7 スコープ

宣言された変数などを参照できる範囲についての説明です。

ブロックは関数やループを囲んでいる {} で囲われた一連の文のことになります。
ブロック内で宣言された変数などはブロック外からは見えません。

具体的な例を出しながら説明されているので、実際に動かしながら見てみるとわかりやすいと思います。

ここでは練習問題はなし!わーいw

2章から結構ボリュームあるなぁ、読み応えあるなぁ、という印象です。
3章は基本データ型について。ここも結構ボリューミィな感じなので、がんばります。