Last active
January 30, 2020 08:21
-
-
Save nasa9084/c4f19bd8b36045d15ee9198650b08628 to your computer and use it in GitHub Desktop.
Revisions
-
nasa9084 revised this gist
Jul 20, 2019 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1150,6 +1150,8 @@ Hint: * コマンドライン引数は[`flag.Arg()`](https://golang.org/pkg/flag#Arg)または[`flag.Args()`](https://golang.org/pkg/flag#Args)を使用して得ることができます。 * 文字列から数値への変換は[`strconv.Atoi()`](https://golang.org/pkg/strconv#Atoi)を使用します。 [回答例](https://play.golang.org/p/l9XykcgRMtO) #### 追加課題 上記仕様でFizzBuzzが実装できた人は、次の仕様で実装してみましょう。 -
nasa9084 revised this gist
Jul 20, 2019 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1476,7 +1476,7 @@ Hint: [net/http](https://golang.org/pkg/net/http)パッケージ内にもファ * POST `/item/create`でアイテムを追加する * DELETE `/item`(ヘッダにitem IDを入れる)でアイテムを削除する Hint: 今回はデータベースの使用方法については学習していませんので、簡単のため[Map](#Map)を使用するとよいでしょう([`database/sql`](https://golang.org/pkg/database/sql)などを使用して、SQLデータベースに値を格納してももちろんかまいません!)。 ### その他 @@ -1486,6 +1486,6 @@ Hint: 今回はデータベースの使用方法については学習してい ## 参考 * [Go](https://golang.org) * [Gopher slack](https://invite.slack.golangbridge.org/) * #japan -
nasa9084 revised this gist
Jul 20, 2019 . 1 changed file with 7 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1482,4 +1482,10 @@ Hint: 今回はデータベースの使用方法については学習してい * [@tenntenn](https://twitter.com/tenntenn)さんによる[ハンズオン資料](https://github.com/tenntenn/gohandson)を使用してアプリケーションを実装してみる: [LINK](https://github.com/tenntenn/gohandson) * [golang.tokyo](https://golangtokyo.github.io/)の[コードラボ](https://golangtokyo.github.io/codelab/)にある資料を見ながら、より実用的なアプリケーションを実装してみる: [LINK](https://golangtokyo.github.io/codelab/) * [Women Who Go Tokyo](https://womenwhogotokyo.github.io/)の[コードラボ](https://womenwhogotokyo.github.io/codelab/)にある資料を見ながら、GCP上でアプリケーションを実行してみる: [LINK](https://womenwhogotokyo.github.io/codelab/) ## 参考 * [Go](https://golang.org] * [Gopher slack](https://invite.slack.golangbridge.org/) * #japan -
nasa9084 revised this gist
Jul 20, 2019 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -86,6 +86,8 @@ Go言語のプログラムは「パッケージ」という単位で開発をし パッケージ名は文字から始まり、文字と数字、`_`(アンダーバー)を使って自由に名前を付けることができます(誰もやりませんが、日本語で名前を付けることもできます)。あまり長くない名前で、`_`や数字を使っていない名前が多いです。 一つのディレクトリには一つのパッケージ(ちょっと例外もありますが)しか入れることはできません。ディレクトリ内の.goファイルはすべて同じパッケージ名を持つようにしてください。 `package`宣言と`import`宣言を終えたら、本体のプログラムを書きます。今回は`main`関数を書きました。 `main`パッケージを実行する際に一番最初に実行されるのが`main()`関数です。関数の定義の仕方などは後述しますが、`func main()`が始めに呼ばれます。C言語などでは引数にコマンドライン引数を受け取ったりしますが、Go言語のプログラムでは受け取りません。返値もない、ただの`func main()`です。覚えやすいですね。 コマンドラインツールなどの実行可能なプログラムを書くときはまず、`main`関数から書き始めるということを覚えておいてください。このあと、いくつかのサンプルプログラムを例示しますが、特に関数定義や説明のない場合は`main`関数の中で実行すると動作を確かめることができます。 -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 31 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1420,7 +1420,7 @@ Go言語では、HTTPに関連した標準パッケージとして[net/http](htt * [`http.HandleFunc()`](https://golang.org/pkg/net/http#HandleFunc): パスと`http.HandlerFunc`の組を渡して、httpパッケージのデフォルトHandlerにHTTPのエンドポイントを設定する関数です。 * [`http.HandlerFunc`](https://golang.org/pkg/net/http#HandlerFunc): 次に説明する`http.ResponseWriter`と`*http.Request`を受け取り、処理をする関数です。`http.HandleFunc`で設定したパスにアクセスがあった場合に呼び出されます。 * [`http.ResponseWriter`](https://golang.org/pkg/net/http#ResponseWriter): サーバがクライアントに対してレスポンスを返すための関数をまとめたinterfaceです。`WriteHeader(int)`でステータスコードを設定し、`Write([]byte)`でbodyをクライアントに送ります。 * [`http.Request`](https://golang.org/pkg/net/http#Request): サーバがクライアントから受けたリクエストに関する情報を含んだ構造体です。MethodやURL、HeaderやBodyなどが含まれます。 * [`http.ListenAndServe()`](https://golang.org/pkg/net/http#ListenAndServe): 実際にサーバを実行し、第一引数で与えたアドレスを第二引数で与えたHandlerで待ち受けます。第二引数がnilなら、httpパッケージのデフォルトHandlerが使われます。 ``` go @@ -1451,4 +1451,33 @@ func main() { $ curl http://localhost:8080/hello ``` `Hello, world`と表示されれば成功です! いくつか案を用意しましたので、次の中から一つ選んで実装してみましょう(もちろん、お好みのネタで実装してみてもOKです)。 ### Website * 自分の自己紹介など、何らかのHTMLページを表示するようなサーバ * 適当なディレクトリにおいたファイルを返す Hint: [net/http](https://golang.org/pkg/net/http)パッケージ内にもファイルをサーブするために使える関数がいろいろ用意されています。 ### 簡易電卓 * 数式を渡すと答えが返ってくる * POST `/calc`(bodyに数式を入れる)で計算をする ### TODO List * TODOリストを管理するアプリケーション * GET `/items`でTODOの一覧を返す * POST `/item/create`でアイテムを追加する * DELETE `/item`(ヘッダにitem IDを入れる)でアイテムを削除する Hint: 今回はデータベースの使用方法については学習していませんので、簡単のため[Map](#Map)を使用するとよいでしょう(`database/sql`などを使用して、SQLデータベースに値を格納してももちろんかまいません!)。 ### その他 * [@tenntenn](https://twitter.com/tenntenn)さんによる[ハンズオン資料](https://github.com/tenntenn/gohandson)を使用してアプリケーションを実装してみる: [LINK](https://github.com/tenntenn/gohandson) * [golang.tokyo](https://golangtokyo.github.io/)の[コードラボ](https://golangtokyo.github.io/codelab/)にある資料を見ながら、より実用的なアプリケーションを実装してみる: [LINK](https://golangtokyo.github.io/codelab/) * [Women Who Go Tokyo](https://womenwhogotokyo.github.io/)の[コードラボ](https://womenwhogotokyo.github.io/codelab/)にある資料を見ながら、GCP上でアプリケーションを実行してみる: [LINK](https://womenwhogotokyo.github.io/codelab/) -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,7 +4,7 @@ Go言語での開発をするために、まずは環境整備をしましょう。 ## Go言語のインストール [公式サイト](https://golang.org/dl/)より、ご自身の環境に合わせてインストーラをダウンロードし、Go言語の実行環境をインストールしてください。 バージョンは最新(本ガイドを書いた時点では1.12.6)をインストールしてください。 @@ -684,7 +684,7 @@ needWriter(mw) ### Channel Go言語の大きな特徴として並行処理が簡単に実装できることが挙げられます。Go言語では[goroutine]を用いることで並行処理を実装します。Channelは並行処理実装の上で、複数の[goroutine](#goroutine)間での値の送受信を行うための型です。CSを勉強した方には、「Queueの様なモノ」と説明すればわかりやすいでしょうか。送受信したい型を`T`とすると、Channelの型は`chan T`と表現します。初期化されていないChannelはnilで、そのままだと使用できませんので、組み込み関数`make()`でChannelを作成します。 ``` go ch := make(chan int) @@ -1183,11 +1183,11 @@ go func() { fmt.Println("hi") ``` 注意点として、今回紹介した様なコード片や、簡単なコマンドラインツール等ではあまり気にしなくても問題ありませんが、goroutineは **leakします**。HTTPサーバ等の継続的に動き続けるアプリケーションでは、goroutineを作成したら適切に終了させないと、自動で削除されることはありません。特に後述するようなfor文と組み合わせて使う場合や、ブロックし続けるような処理を含んでいる場合には、必ず適切な処理を行ってください(例えば、後述する[context.Context](#context.Context)などでキャンセルする、などが有効です)。 ### chan 前述の様に、goroutineは`go 関数()`の形で呼び出します。これは(呼び出した関数が返値を持っていても)値を返さないため、何らかの値を得るためには返値ではない、別の方法を使用する必要があります。そのときに利用できるのが、[Channel](#Channel)の節で紹介したChannelです。Channelはgoroutine間(`main()`が実行されているのも実はgoroutineの一つです)で値をやりとりするための仕組みです。 Channelは送信側/受信側ともに準備ができた状態になるまではブロック(処理が進まなくなる)します。そのため、Channelはgoroutine間の処理の同期に使用することができます。[play](https://play.golang.org/p/nPFfRivvkJr) -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -544,7 +544,7 @@ type Person struct { } ``` 構造体は複合[リテラル](#リテラル)を使って初期化することができます。また、それぞれのフィールドへは`.`(ドット)を使ってアクセスすることができます。[play](https://play.golang.org/p/fUVDYNC3nP7) ``` go // https://play.golang.org/p/fUVDYNC3nP7 -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 35 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -608,7 +608,42 @@ fmt.Println(myCar.IsRunning) ### Pointer ポインタはあるデータ(すべての型が対象です)の実体(メモリ上でのアドレス)を指す型です。「文字列のポインタ」や「intのポインタ」など、「xxxのポインタ」という形で呼びます。 ポインタをとりたいある型をTとすると、Tのポインタは`*T`と書きます。 ``` go var pi *int // intのポインタ var si *string // stringのポインタ type Person struct { /* ... */ } var pp *Person // Personのポインタ ``` また、ある変数やある値のポインタを取得するためには、`&`演算子を使用します。[play](https://play.golang.org/p/2DW-pYgMF_Y) ``` go // https://play.golang.org/p/2DW-pYgMF_Y i := 10 fmt.Println(&i) // iのポインタ(アドレス)を表示 ``` 逆に、ポインタから値を得たい場合は`*`演算子を使用します。[play](https://play.golang.org/p/Cn47DrOwLfy) ``` go // https://play.golang.org/p/Cn47DrOwLfy var sp *string s := "hello" sp = &s fmt.Println(*sp) // Output: // hello ``` ポインタ型を定義するときも`*`を使用し、ポインタから値をとるときも`*`を使用するので、混乱しがちなので頑張りましょう。 ### interface -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 12 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -313,7 +313,7 @@ Go言語の変数は必ず型を持っています。変数の型によって格 #### 文字列の長さ: `len()`関数 文字列の長さ(byte数)を取得するには、組み込み関数である[`len()`](https://golang.org/pkg/builtin#len)関数が使用できます。[play](https://play.golang.org/p/CwOQ6KZkjKM) ``` go // https://play.golang.org/p/CwOQ6KZkjKM @@ -350,13 +350,13 @@ fmt.Println(len([]rune(s))) Go言語の標準パッケージには文字列を取り扱うものが多くあります。代表的なモノとして次の様なものがあります。 * [`bytes`](https://golang.org/pkg/bytes)/[`strings`](https://golang.org/pkg/strings) + 文字列の分割や結合など、標準的な文字列処理をひとまとめにしたパッケージです。`bytes`と`strings`はそれぞれ`[]byte`型と`string`型を対象としており、おおよそ同じ関数が用意されています。 * [`strconv`](https://golang.org/pkg/strconv) + 文字列と他の型(数値や真偽値)とを変換するための関数をまとめたパッケージです。 * [`unicode`](https://golang.org/pkg/unicode) + Unicodeのコードポイントを取り扱うためのパッケージです。特にその文字がどういった文字であるかを判別する`IsXXX`という形の関数が充実しています。 * [`regexp`](https://golang.org/pkg/regexp) + 正規表現を取り扱うためのパッケージです。 ### 配列/Slice @@ -399,7 +399,7 @@ var sliceInt []int #### 要素の追加: `append()`関数 配列は長さが変更できないため、要素の追加をすることはできないのですが、Sliceではできます。その際には、組み込み関数である[`append()`](https://golang.org/pkg/builtin#append)を使用します。`append()`は第一引数に任意のSlice、第二引数に追加したい要素を取り、Sliceに要素を追加した新しいSliceを返します。元のSlice(第一引数に与えられたもの)は変更されません。元の配列に追加したい場合には次の様にします。[play](https://play.golang.org/p/hocpa8Y4YiU) ``` go // https://play.golang.org/p/hocpa8Y4YiU @@ -544,7 +544,7 @@ type Person struct { } ``` 構造体は複合[リテラル][#リテラル]を使って初期化することができます。また、それぞれのフィールドへは`.`(ドット)を使ってアクセスすることができます。[play](https://play.golang.org/p/fUVDYNC3nP7) ``` go // https://play.golang.org/p/fUVDYNC3nP7 @@ -649,7 +649,7 @@ needWriter(mw) ### Channel Go言語の大きな特徴として並行処理が簡単に実装できることが挙げられます。Go言語では[goroutine]を用いることで並行処理を実装します。Channelは並行処理実装の上で、複数の[goroutine][#goroutine]間での値の送受信を行うための型です。CSを勉強した方には、「Queueの様なモノ」と説明すればわかりやすいでしょうか。送受信したい型を`T`とすると、Channelの型は`chan T`と表現します。初期化されていないChannelはnilで、そのままだと使用できませんので、組み込み関数`make()`でChannelを作成します。 ``` go ch := make(chan int) @@ -1110,8 +1110,8 @@ Buzz * 表示する数字が3の倍数で、かつ5の倍数でもあるなら、数字を表示する代わりに"FizzBuzz"を表示する Hint: * コマンドライン引数は[`flag.Arg()`](https://golang.org/pkg/flag#Arg)または[`flag.Args()`](https://golang.org/pkg/flag#Args)を使用して得ることができます。 * 文字列から数値への変換は[`strconv.Atoi()`](https://golang.org/pkg/strconv#Atoi)を使用します。 #### 追加課題 @@ -1148,11 +1148,11 @@ go func() { fmt.Println("hi") ``` 注意点として、今回紹介した様なコード片や、簡単なコマンドラインツール等ではあまり気にしなくても問題ありませんが、goroutineは **leakします**。HTTPサーバ等の継続的に動き続けるアプリケーションでは、goroutineを作成したら適切に終了させないと、自動で削除されることはありません。特に後述するようなfor文と組み合わせて使う場合や、ブロックし続けるような処理を含んでいる場合には、必ず適切な処理を行ってください(例えば、後述する[context.Context][#context.Context]などでキャンセルする、などが有効です)。 ### chan 前述の様に、goroutineは`go 関数()`の形で呼び出します。これは(呼び出した関数が返値を持っていても)値を返さないため、何らかの値を得るためには返値ではない、別の方法を使用する必要があります。そのときに利用できるのが、[Channel][#Channel]の節で紹介したChannelです。Channelはgoroutine間(`main()`が実行されているのも実はgoroutineの一つです)で値をやりとりするための仕組みです。 Channelは送信側/受信側ともに準備ができた状態になるまではブロック(処理が進まなくなる)します。そのため、Channelはgoroutine間の処理の同期に使用することができます。[play](https://play.golang.org/p/nPFfRivvkJr) -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 26 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1225,7 +1225,7 @@ syncパッケージは非同期処理における同期処理の仕組みをい #### sync.WaitGroup [`sync.WaitGroup`](https://golang.org/pkg/sync#WaitGroup)はその名の通り、goroutineをグループ化して、そのすべてのgoroutineが終了するのを待つために使用する構造体です。特に初期化することなく使用可能です。[`WaitGroup.Add(1)`](https://golang.org/pkg/sync#WaitGroup.Add)でgoroutineの数を追加し、待ちたいgoroutineが処理終了する際に[`WaitGroup.Done()`](https://golang.org/pkg/sync#WaitGroup.Done)を呼びます。[`WaitGroup.Wait()`](https://golang.org/pkg/sync#WaitGroup.Wait)は`Add()`した回数`Done()`が呼ばれるまでブロックします。注意点として、goroutineは **呼び出したその場で処理が開始するとは限らない** ため、`Add()`はgoroutineの外で呼び、`Done()`はgoroutineの中で呼ぶようにします。[play](https://play.golang.org/p/EfpiGlkLOvx) ``` go // https://play.golang.org/p/EfpiGlkLOvx @@ -1246,7 +1246,7 @@ fmt.Println("all goroutine have finished") #### sync.Mutex [`sync.Mutex`](https://golang.org/pkg/sync#Mutex)は排他制御のために使用される構造体です。[`Lock()`](https://golang.org/pkg/sync#Mutex.Lock)と[`Unlock()`](https://golang.org/pkg/sync#Mutex.Unlock)の二つのメソッドを持っています。`Lock()`を呼んだとき、他の場所ですでに`Lock()`が呼ばれている場合、`Unlock()`が呼ばれるまでブロックします。そのため、`sync.Mutex`を使用することである変数などが複数のgoroutineから変更されることを防ぐことができます。ゼロ値の`sync.Mutex`はそのまま(特に初期化等することなく)使用することができます。[play](https://play.golang.org/p/jyDti7pQYLT) ``` go // https://play.golang.org/p/jyDti7pQYLT @@ -1290,7 +1290,7 @@ wg.Wait() ### context.Context [context.Context](https://golang.org/pkg/context#Context)は主としてgoroutineのキャンセル処理などに使用される構造体です。上位のgoroutineがキャンセルされた場合(例えば、signalを受けてアプリケーションを終了する、HTTPのリクエストがキャンセルされた、など)、下位のgoroutineにキャンセルを伝搬する機能も持っています。通常、context.Contextを得るには、`context.Background()`を使用します。そのほか、[`context.WithCancel()`](https://golang.org/pkg/context#WithCancel)、[`context.WithDeadline()`](https://golang.org/pkg/context#WithDeadline)、[`context.WithTimeout()`](https://golang.org/pkg/context#WithTimeout)を使用することでキャンセル処理、タイムアウト処理を簡単に実装することができます。 コンテキストがキャンセルされた場合、`Context.Done()`で帰ってくるチャンネルが閉じられるため、select文でコンテキストの終了を検知することができます。次の例では、goroutineで1秒ごとにカウントアップし、10秒後に`main()`からキャンセルします。[play](https://play.golang.org/p/T3L5QZkV4NB) @@ -1317,7 +1317,7 @@ time.Sleep(10 * time.Second) cancel() ``` 実際には上記のキャンセル処理はHTTPリクエストのキャンセルや、エラーが発生した時などに行われます。このようなケースでは[`context.WithTimeout()`](https://golang.org/pkg/context#WithTimeout)を使用して実装する方がよいでしょう。[play](https://play.golang.org/p/IztyGR0PTPP) ``` go // https://play.golang.org/p/IztyGR0PTPP @@ -1380,19 +1380,25 @@ Hint: さて、いくつか端折ってきた部分もありますが、これで一通りGo言語の仕様については学んできました。ここで、簡単なWebアプリケーションを一つ実装してみましょう。 Go言語では、HTTPに関連した標準パッケージとして[net/http](https://golang.org/pkg/net/http)が用意されています。そのうち、今回のように簡単なWebアプリケーションの実装をするにあたり重要なものとして、次のものが挙げられます: * [`http.HandleFunc()`](https://golang.org/pkg/net/http#HandleFunc): パスと`http.HandlerFunc`の組を渡して、httpパッケージのデフォルトHandlerにHTTPのエンドポイントを設定する関数です。 * [`http.HandlerFunc`](https://golang.org/pkg/net/http#HandlerFunc): 次に説明する`http.ResponseWriter`と`*http.Request`を受け取り、処理をする関数です。`http.HandleFunc`で設定したパスにアクセスがあった場合に呼び出されます。 * [`http.ResponseWriter`](https://golang.org/pkg/net/http#ResponseWriter): サーバがクライアントに対してレスポンスを返すための関数をまとめたinterfaceです。`WriteHeader(int)`でステータスコードを設定し、`Write([]byte)`でbodyをクライアントに送ります。 * [`http.Request`](https://golang.org/pkg/net/http#Request): サーバがクライアントから受けたリクエストに関する情報を含んだ構造体です。MethodやURL、Bodyなどが含まれます。 * [`http.ListenAndServe()`](https://golang.org/pkg/net/http#ListenAndServe): 実際にサーバを実行し、第一引数で与えたアドレスを第二引数で与えたHandlerで待ち受けます。第二引数がnilなら、httpパッケージのデフォルトHandlerが使われます。 ``` go package main import ( "fmt" "net/http" ) // Hello はhttp.HandlerFuncを実装している関数 func Hello(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) // 200 OKを設定 w.Write([]byte("Hello, world")) // bodyとしてメッセージを送信 } func main() { @@ -1402,4 +1408,12 @@ func main() { fmt.Println(err.Error()) } } ``` 上記のコードを実行すると、`:8080`でHTTPサーバが待ち受けます。上記コードを実行したのとは別の端末を起動し、次の様に動作を確認してみましょう。 ``` shell $ curl http://localhost:8080/hello ``` `Hello, world`と表示されれば成功です! -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 25 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1378,4 +1378,28 @@ Hint: ## 簡単なアプリケーションの実装 さて、いくつか端折ってきた部分もありますが、これで一通りGo言語の仕様については学んできました。ここで、簡単なWebアプリケーションを一つ実装してみましょう。 Go言語では、HTTPに関連した標準パッケージとしてnet/httpが用意されています。そのうち、今回のように簡単なWebアプリケーションの実装をするにあたり重要なものとして、次のものが挙げられます: * `http.HandleFunc()`: パスと`http.HandlerFunc`の組を渡して、httpパッケージのデフォルトHandlerにHTTPのエンドポイントを設定する関数です。 * `http.HandlerFunc`: `http.ResponseWriter`と`*http.Request`を受け取り、処理をする関数です。 * `http.ResponseWriter`: サーバがクライアントに対してレスポンスを返すための関数をまとめたinterfaceです。`WriteHeader(int)`でステータスコードを設定し、`Write([]byte)`でbodyをクライアントに送ります。 * `http.Request`: サーバがクライアントから受けたリクエストに関する情報を含んだ構造体です。MethodやURL、Bodyなどが含まれます。 * `http.ListenAndServe()`: 実際にサーバを実行し、第一引数で与えたアドレスを第二引数で与えたHandlerで待ち受けます。第二引数がnilなら、httpパッケージのデフォルトHandlerが使われます。 ``` go // Hello はhttp.HandlerFuncを実装している関数 func Hello(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) // 200 OKを設定 w.WriteHeader([]byte("Hello, world")) // bodyとしてメッセージを送信 } func main() { http.HandleFunc("/hello", Hello) // /hello というパスにリクエストが来たらHelloを呼ぶ if err := http.ListenAndServe(":8080", nil); err != nil { // :8080で待ち受ける fmt.Println(err.Error()) } } ``` -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 10 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1217,6 +1217,7 @@ for { } ``` また、if文におけるelse処理のようにどのケースも当てはまらない場合には`default`というケースを作成することで、「その他」の処理を記述することもできます。 ### syncパッケージ @@ -1345,7 +1346,7 @@ go func(ctx context.Context) { * New関数でChannelを得る * New関数の引数は自由 * 得られたChannelからはintの値が1から順番に得られる * 任意のタイミングでgeneratorの利用を終了できる * 使用例(キャンセル処理を含んでいません): @@ -1356,19 +1357,25 @@ for i := range generator { fmt.Println(i) } // Output: // 1 // 2 // 3 // ...と永遠に表示され続ける ``` Hint: * `close()`した後のChannelに値を入れようとするとpanic(プログラムの異常終了)するので、注意しましょう * 任意のタイミングで終了 = goroutineをキャンセル [回答例](https://play.golang.org/p/UFe7IANh31n) #### FizzBuzzと組み合わせる * `NewFizzBuzzGenerator`関数 * 1, 2, 3, ...の代わりに1, 2, Fizz, ... [回答例](https://play.golang.org/p/sNlzmXJ4uGj) ## 簡単なアプリケーションの実装 さて、いくつか端折ってきた部分もありますが、これで一通りGo言語の仕様については学んできました。ここで、簡単なWebアプリケーションを一つ実装してみましょう。 -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 82 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1148,6 +1148,8 @@ go func() { fmt.Println("hi") ``` 注意点として、今回紹介した様なコード片や、簡単なコマンドラインツール等ではあまり気にしなくても問題ありませんが、goroutineは **leakします**。HTTPサーバ等の継続的に動き続けるアプリケーションでは、goroutineを作成したら適切に終了させないと、自動で削除されることはありません。特に後述するようなfor文と組み合わせて使う場合や、ブロックし続けるような処理を含んでいる場合には、必ず適切な処理を行ってください(例えば、後述する[context.Context]などでキャンセルする、などが有効です)。 ### chan 前述の様に、goroutineは`go 関数()`の形で呼び出します。これは(呼び出した関数が返値を持っていても)値を返さないため、何らかの値を得るためには返値ではない、別の方法を使用する必要があります。そのときに利用できるのが、[Channel]の節で紹介したChannelです。Channelはgoroutine間(`main()`が実行されているのも実はgoroutineの一つです)で値をやりとりするための仕組みです。 @@ -1215,6 +1217,7 @@ for { } ``` ### syncパッケージ syncパッケージは非同期処理における同期処理の仕組みをいくつか提供している標準パッケージです。ここではよく使われるものをいくつか紹介します。 @@ -1286,8 +1289,86 @@ wg.Wait() ### context.Context context.Contextは主としてgoroutineのキャンセル処理などに使用される構造体です。上位のgoroutineがキャンセルされた場合(例えば、signalを受けてアプリケーションを終了する、HTTPのリクエストがキャンセルされた、など)、下位のgoroutineにキャンセルを伝搬する機能も持っています。通常、context.Contextを得るには、`context.Background()`を使用します。そのほか、`context.WithCancel()`、`context.WithDeadline()`、`context.WithTimeout()`を使用することでキャンセル処理、タイムアウト処理を簡単に実装することができます。 コンテキストがキャンセルされた場合、`Context.Done()`で帰ってくるチャンネルが閉じられるため、select文でコンテキストの終了を検知することができます。次の例では、goroutineで1秒ごとにカウントアップし、10秒後に`main()`からキャンセルします。[play](https://play.golang.org/p/T3L5QZkV4NB) ``` go // https://play.golang.org/p/T3L5QZkV4NB ctx, cancel := context.WithCancel(context.Background()) go func(ctx context.Context) { var i int for { select { case <-ctx.Done(): // cancel()が呼ばれるとここに入る fmt.Println("canceled") return case <-time.After(1 * time.Second): fmt.Println(i) i++ } } }(ctx) time.Sleep(10 * time.Second) cancel() ``` 実際には上記のキャンセル処理はHTTPリクエストのキャンセルや、エラーが発生した時などに行われます。このようなケースでは`context.WithTimeout()`を使用して実装する方がよいでしょう。[play](https://play.golang.org/p/IztyGR0PTPP) ``` go // https://play.golang.org/p/IztyGR0PTPP ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second) defer cancel() go func(ctx context.Context) { var i int for { select { case <-ctx.Done(): // タイムアウトでここに入る fmt.Println("timeout") return case <-time.After(1 * time.Second): fmt.Println(i) i++ } } }(ctx) ``` ### goroutineを用いたgenerator 比較的簡単な例として、goroutineを用いたgeneratorを作ってみましょう。次の様な仕様で実装してみてください。 * New関数でChannelを得る * New関数の引数は自由 * 得られたChannelからはintの値が0から順番に得られる * 任意のタイミングでgeneratorの利用を終了できる * 使用例(キャンセル処理を含んでいません): ``` go generator := New(/* 引数は自由に決めてください */) for i := range generator { fmt.Println(i) } // Output: // 0 // 1 // 2 // ...と永遠に表示され続ける ``` Hint: * `close()`した後のChannelに値を入れようとするとpanic(プログラムの異常終了)するので、注意しましょう * 任意のタイミングで終了 = goroutineをキャンセル #### FizzBuzzと組み合わせる * `NewFizzBuzzGenerator`関数 * 1, 2, 3, ...の代わりに1, 2, Fizz, ... ## 簡単なアプリケーションの実装 -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1286,6 +1286,8 @@ wg.Wait() ### context.Context context.Contextは主としてgoroutineのキャンセル処理などに使用される構造体です。上位のgoroutineがキャンセルされた場合(例えば、signalを受けてアプリケーションを終了する、HTTPのリクエストがキャンセルされた、など)、下位のgoroutineにキャンセルを伝搬する機能も持っています。 ### goroutineを用いたgenerator ## 簡単なアプリケーションの実装 -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 79 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1103,13 +1103,24 @@ Buzz 今回は次の様な仕様で実装してみましょう。 * 1からNまでについて数字を順に表示する * Nはコマンドライン引数からとる * 表示する数字が3の倍数なら、数字を表示する代わりに"Fizz"を表示する * 表示する数字が5の倍数なら、数字を表示する代わりに"Buzz"を表示する * 表示する数字が3の倍数で、かつ5の倍数でもあるなら、数字を表示する代わりに"FizzBuzz"を表示する Hint: * コマンドライン引数は[`flag.Arg()`または`flag.Args()`](https://golang.org/pkg/flag/#Arg)を使用して得ることができます。 * 文字列から数値への変換は[`strconv.Atoi()`](https://golang.org/pkg/strconv/#Atoi)を使用します。 #### 追加課題 上記仕様でFizzBuzzが実装できた人は、次の仕様で実装してみましょう。 * 1からNまでについて数字を順に表示する * Nはコマンドライン引数からとる * 表示する数字が3の倍数か、3を含む数字なら、数字を表示する代わりに"Fizz"を表示する ## goroutineを用いた並行処理 Go言語の非常に大きな特徴として、言語の仕様レベルで並行処理をサポートしていることが挙げられます。他の言語では使うこと自体が少々面倒なことも多い並行処理が、Go言語ではとても簡単に並行処理を使ったプログラムを書くことができます。 @@ -1206,6 +1217,73 @@ for { ### syncパッケージ syncパッケージは非同期処理における同期処理の仕組みをいくつか提供している標準パッケージです。ここではよく使われるものをいくつか紹介します。 #### sync.WaitGroup sync.WaitGroupはその名の通り、goroutineをグループ化して、そのすべてのgoroutineが終了するのを待つために使用する構造体です。特に初期化することなく使用可能です。`WaitGroup.Add(1)`でgoroutineの数を追加し、待ちたいgoroutineが処理終了する際に`WaitGroup.Done()`を呼びます。`WaitGroup.Wait()`は`Add()`した回数`Done()`が呼ばれるまでブロックします。注意点として、goroutineは **呼び出したその場で処理が開始するとは限らない** ため、`Add()`はgoroutineの外で呼び、`Done()`はgoroutineの中で呼ぶようにします。[play](https://play.golang.org/p/EfpiGlkLOvx) ``` go // https://play.golang.org/p/EfpiGlkLOvx var wg sync.WaitGroup // 初期化なしで使用できる for _, name := range []string{"Alice", "Bob", "Chris"} { wg.Add(1) // goroutineの前で呼ぶ go func(name string) { defer wg.Done() // goroutine終了。deferが便利です fmt.Println("hello, " + name) }(name) } wg.Wait() // すべてのgoroutineが終わるまで待つ fmt.Println("all goroutine have finished") ``` #### sync.Mutex sync.Mutexは排他制御のために使用される構造体です。`Lock()`と`Unlock()`の二つのメソッドを持っています。`Lock()`を呼んだとき、他の場所ですでに`Lock()`が呼ばれている場合、`Unlock()`が呼ばれるまでブロックします。そのため、sync.Mutexを使用することである変数などが複数のgoroutineから変更されることを防ぐことができます。ゼロ値のsync.Mutexはそのまま(特に初期化等することなく)使用することができます。[play](https://play.golang.org/p/jyDti7pQYLT) ``` go // https://play.golang.org/p/jyDti7pQYLT var wg sync.WaitGroup // sync.Mutexなしのばあい for i := 0; i < 3; i++ { wg.Add(1) go func() { fmt.Println("A") time.Sleep(1 * time.Millisecond) fmt.Println("B") time.Sleep(1 * time.Millisecond) fmt.Println("C") wg.Done() }() } wg.Wait() fmt.Println("----") // sync.Mutexありのばあい var mu sync.Mutex // 初期化なしで使える for i := 0; i < 3; i++ { wg.Add(1) go func() { mu.Lock() defer mu.Unlock() fmt.Println("A") time.Sleep(1 * time.Millisecond) fmt.Println("B") time.Sleep(1 * time.Millisecond) fmt.Println("C") wg.Done() }() } wg.Wait() ``` ### context.Context ### goroutineを用いたgenerator -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 193 additions and 21 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -561,9 +561,11 @@ fmt.Println(alice.Age) フィールドの名前を小文字で始めた場合は、普通の変数等と同様に、パッケージの外からは直接アクセスできなくなります。 フィールドに加えて、構造体はメソッドと呼ばれる関数を持つことができます。メソッドはフィールドと同様、`.`(ドット)を使って呼び出すことができます。 メソッドの定義は、関数定義とほとんど同じで、関数名の前にレシーバーと呼ばれる、構造体の受け取り情報を記述します。[play](https://play.golang.org/p/J-EzWvR9bXh) ``` go // https://play.golang.org/p/J-EzWvR9bXh func (p Person) IsYoung() bool { return p.Age < 30 } @@ -577,9 +579,11 @@ fmt.Print(alice.IsYoung()) // true ``` レシーバーとしては、構造体の値ではなく、ポインタを指定することができます。ポインタを指定した時に限り、メソッド内でレシーバーの状態を変化させることができます。[play](https://play.golang.org/p/CB5K2-qdSpW) ``` go // https://play.golang.org/p/CB5K2-qdSpW type Car struct { IsRunning bool } @@ -588,7 +592,7 @@ func (car Car) RunWithValue() { car.IsRunning = true // メソッド外では影響がない } func (car *Car) RunWithPointer() { car.IsRunning = true // 元の値を書き換える } @@ -616,7 +620,32 @@ type Reader interface { } ``` `*bytes.Buffer`構造体や`*os.File`構造体はこれを満たしているため、`io.Reader`を要求する関数などに対して`*bytes.Buffer`や`*os.File`を使用することができます。また、自分でこれを満たす様な構造体を実装することもできます。`io.Writer`を簡単に実装してみましょう。[play](https://play.golang.org/p/Yvf0E8T2Lz1) ``` go // https://play.golang.org/p/Yvf0E8T2Lz1 // io.Writerは次の様に定義されている // type Writer interface { // Write([]byte) (int, error) // } type myWriter struct {} // 特にio.Writerを実装していることを明示しているわけではない func (w myWriter) Write(b []byte) (int, error) { fmt.Println(string(b)) return len(b), nil } func needWriter(w io.Writer) { w.Write([]byte("Hello")) } mw := myWriter{} needWriter(mw) // Output: // Hello ``` ### Channel @@ -626,7 +655,7 @@ Go言語の大きな特徴として並行処理が簡単に実装できること ch := make(chan int) ``` Channelは「送る(Send)」と「受け取る(Receive)」の二つの操作をすることができます。これらの操作には`<-`演算子を使用します。Channel変数の左側に`<-`を書いた場合は受け取り、右側に書いたときは送信です。[play](https://play.golang.org/p/HHZD7xKjtnE) ``` go // https://play.golang.org/p/HHZD7xKjtnE @@ -642,7 +671,7 @@ fmt.Println(<-ch) // 10 ``` 送信側は値が受け取られるまで、受信側は値が来るまで、ブロック(待機)します。そのため、受け取り側しかない、同じgoroutineで送信と受け取りの両方を行おうとしている、などの場合、[deadlock](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%83%E3%83%89%E3%83%AD%E3%83%83%E3%82%AF)することもあるので注意しましょう。[play](https://play.golang.org/p/qeRi4FuenwC) ``` go // https://play.golang.org/p/qeRi4FuenwC @@ -655,7 +684,7 @@ Channelにはバッファを用意することもできますが、ほとんど #### Channelを閉じる: `close()`関数 送信側から、「これ以上値を送りませんよ」ということを伝えるため、Channelは「閉じる」ことができます。その際に使用するのが組み込み関数である`close()`です。受信側がChannelに対してfor-range(後述)を使用して読み込みしている場合などには、Channelきちんと閉じることで適切に処理を続行することができます。[play](https://play.golang.org/p/qjsB8MK9QrG) ``` go // https://play.golang.org/p/qjsB8MK9QrG @@ -674,7 +703,7 @@ for v := range ch { fmt.Println("finished") ``` 一方、閉じた後のChannelに対して値を送信しようとしたり、閉じたChannelをさらに閉じようとするとプログラムが異常終了しますので、注意が必要です。なお、閉じた後のChannelから読み出しをした場合はブロックせずにゼロ値が返ります。[play](https://play.golang.org/p/0KS_K0yUmvh) ``` go // https://play.golang.org/p/0KS_K0yUmvh @@ -727,15 +756,19 @@ if [初期化文; ]条件式 { } ``` 複数の条件式すべてを満たす時に処理をしたい場合(AND)には、演算子`&&`を、いずれかの条件を満たしているときに処理をしたい場合(OR)には、演算子`||`を使用します。[play](https://play.golang.org/p/_iJta1Dg4CM) ``` go // https://play.golang.org/p/_iJta1Dg4CM if foo == 1 && bar == 2 { // 変数fooが1で変数barが2の時に実行される fmt.Println("foo is 1 and bar is 2") } if baz < 100 || 200 < baz { // 変数bazが100未満か200より大きいときに実行される fmt.Println("baz is under 100 or over 200") } ``` @@ -768,25 +801,32 @@ default: // defaultは省略可能 } ``` switch/case文は上から順番に式を評価していき、最初に`switchの式 == caseの式`が`true`のものを実行します。[play](https://play.golang.org/p/GbOtt0GibQs) ``` go // https://play.golang.org/p/GbOtt0GibQs switch version { case "1.0.0": // version == "1.0.0"の時の処理 fmt.Println("version 1.0.0") case "2.0.0": // version == "2.0.0"の時の処理 fmt.Println("version 2.0.0") } ``` caseの式には複数の値をカンマ区切りで指定することができます。[play](https://play.golang.org/p/SvoGCz1O6Ii) ``` go // https://play.golang.org/p/SvoGCz1O6Ii switch userType { case "admin", "manager": // userTypeが"admin"か"manager"の時の処理 fmt.Println("you're super user") case "user": // userTypeが"user"の時の処理 fmt.Println("you're regular user") } ``` @@ -829,7 +869,7 @@ case quux == corge: } ``` 複数の`if-if elese`をつなげるより、こちらの方が簡潔でかつ読みやすく記述できる場合があります。 ### for @@ -852,12 +892,25 @@ for [初期化文]; [条件式]; [再初期化文] { 4. 処理終了後、再初期化分を実行する。通常は初期化文で初期化した変数に再代入するなどして状況を更新する。 5. 2.にもどる 例として次のプログラムは1から10までの数字を表示します。[play](https://play.golang.org/p/hv-JoJMyt8z) ``` go // https://play.golang.org/p/hv-JoJMyt8z for i := 0; i < 10; i++ { fmt.Println(i + 1) } // Output: // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 8 // 9 // 10 ``` 初期化文、条件式、再初期化文はいずれも省略することができます。 @@ -871,7 +924,28 @@ for [条件式] { } ``` まず条件式が評価され、結果が`true`ならば処理を行い、再度条件式を評価し・・・というのを、条件式の結果が`false`となるまで繰り返します。次の例は先ほどと同様、1から10まで表示します。 ``` go // https://play.golang.org/p/xEryTwzfpWp i := 0 for i < 10 { fmt.Println(i + 1) i++ } // Output: // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 8 // 9 // 10 ``` #### for-range構文 @@ -899,9 +973,11 @@ for i := range arr { } ``` 配列/Sliceに対してfor-rangeを使用する場合、値は二つ返ってきます。一つ目は配列/Sliceの添え字(int)で、二つ目はそのインデックスで得られる値です。[play](https://play.golang.org/p/_fkQhEMzEfc) ``` go // https://play.golang.org/p/_fkQhEMzEfc arr := []string{"foo", "bar", "baz"} for i, elem := range arr { fmt.Println(i, elem) @@ -912,18 +988,28 @@ for i, elem := range arr { // 2 baz ``` 文字列は`[]byte`とほぼ等しいですが、`[]byte`に対してfor-rangeを使用すると二つ目の値として`byte`が得られる(つまり、文字単位のループにはならない)一方、文字列に対してfor-rangeを使用すると二つ目の値として`rune`が得られます。これはUTF-8の文字単位でループすることが可能と言うことです。ただし、一つ目の値はバイト数なので注意してください。[play](https://play.golang.org/p/uBBa_qV40q4) ``` go // https://play.golang.org/p/uBBa_qV40q4 s := "こんにちは" for i, elem := range s { fmt.Printf("%d %c\n",i, elem) // %dは10進数の整数を、%cは文字(rune)を表示するためのフォーマット } // Output: // 0 こ // 3 ん // 6 に // 9 ち // 12 は ``` Mapに対してfor-rangeを使用する場合、一つ目の値としてキーが、二つ目の値として対応する値が得られます。[play](https://play.golang.org/p/AIqb4C1Bc2a) ``` go // https://play.golang.org/p/AIqb4C1Bc2a m := map[string]string{ "foo": "hoge", "bar": "fuga", @@ -938,9 +1024,11 @@ for k, v := range m { // baz piyo ``` Channelに対してfor-rangeを使用した場合、値は一つで、Channelから送られてきた値が得られます。Channelがcloseされるまでループを抜けないため、注意が必要です。[play](https://play.golang.org/p/l9hzUXfxyaH) ``` go // https://play.golang.org/p/l9hzUXfxyaH ch := chMaker() for v := range ch { fmt.Println(v) @@ -965,7 +1053,17 @@ func 関数名() { 2. 処理2 3. 後処理() となります。複数`defer`を使った場合は、下から順に実行されます。関数内の処理自体は上から下ですから、上から順に実行されていき、returnまたは関数の最後に到達したらまた上に戻っていく、という流れだと思えばいいでしょう。[play](https://play.golang.org/p/i1ckJXs1zBp) ``` go // https://play.golang.org/p/i1ckJXs1zBp fmt.Println("first") defer fmt.Println("fifth") fmt.Println("second") defer fmt.Println("fourth") fmt.Println("third") ``` ### エラー処理 @@ -1026,12 +1124,86 @@ go 関数() たったこれだけで、任意の関数を並行起動することができます。 注意しなければならないのは、 **`main`関数が終了したらプログラムの実行自体が終わる、ということ** です。goroutineがいくつ起動されていようとも、`main`関数の終了とともにすべてが終了します。そのため、通常は何らかの方法で(後述します)goroutineとの待ち合わせ(同期)を行います。次の例では、goroutineの中で文字列の出力が行われていますが、`main`関数のほうが先に終わってしまうため、"this is goroutine"が出力されません。[play](https://play.golang.org/p/dzGSP5Pbilb) ``` go // https://play.golang.org/p/dzGSP5Pbilb fmt. Println("hello") go func() { time.Sleep(5 * time.Second) // 5秒休む: 長時間かかる処理の代わり fmt.Println("this is goroutine") }() fmt.Println("hi") ``` ### chan 前述の様に、goroutineは`go 関数()`の形で呼び出します。これは(呼び出した関数が返値を持っていても)値を返さないため、何らかの値を得るためには返値ではない、別の方法を使用する必要があります。そのときに利用できるのが、[Channel]の節で紹介したChannelです。Channelはgoroutine間(`main()`が実行されているのも実はgoroutineの一つです)で値をやりとりするための仕組みです。 Channelは送信側/受信側ともに準備ができた状態になるまではブロック(処理が進まなくなる)します。そのため、Channelはgoroutine間の処理の同期に使用することができます。[play](https://play.golang.org/p/nPFfRivvkJr) ``` go // https://play.golang.org/p/nPFfRivvkJr ch := make(chan string) go func() { time.Sleep(5 * time.Second) // 5秒休む ch <- "Hello" }() s := <- ch // chから値が送られてくるまで待つ fmt.Println(s) ``` ### select/case `select`文は`switch`文に非常によく似ていますが、複数のChannelで一番最初に処理されたものを選択するための構文です。まずは例を見てみましょう。[play](https://play.golang.org/p/1ygDWPQ91Gt) ``` go // https://play.golang.org/p/1ygDWPQ91Gt ch := make(chan string) go func() { time.Sleep(5 * time.Second) // 長い処理 ch <- "Hello" }() select { case s := <-ch: fmt.Println(s) case <-time.After(3 * time.Second): // time.Afterはchan time.Timeを返し、指定した時間の後に値が送られてくる fmt.Println("3 seconds passed") } ``` 上記の例では、二つ目のcaseの方が先に受信成功するため、"3 seconds passed"がプリントされます。select文ではすべてのcaseは同時に待ち受けられます。 また、上記は例のためselect分単体で使用しましたが、多くのケースでは条件を指定していない(=無限ループする)for文と併せて利用されます。[play](https://play.golang.org/p/Iab77qnSTjy) ``` go // https://play.golang.org/p/Iab77qnSTjy done := make(chan struct{}) go func() { time.Sleep(3 * time.Second) done <- struct{}{} close(done) }() for { select { case <-time.After(1 * time.Second): fmt.Println("1 second passed") case <-done: fmt.Println("done!") return } } ``` ### syncパッケージ ### context.Context -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -544,9 +544,11 @@ type Person struct { } ``` 構造体は複合[リテラル]を使って初期化することができます。また、それぞれのフィールドへは`.`(ドット)を使ってアクセスすることができます。[play](https://play.golang.org/p/fUVDYNC3nP7) ``` go // https://play.golang.org/p/fUVDYNC3nP7 alice := Person{ Name: "Alice", Age: 20, -
nasa9084 revised this gist
Jul 18, 2019 . 1 changed file with 29 additions and 26 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -147,7 +147,7 @@ var X = 0 var X int ``` もう一つは`:=`を使った方法で、関数内でのみ使用することができます。[play](https://play.golang.org/p/Fen0IU5gfQ0) ``` go // https://play.golang.org/p/Fen0IU5gfQ0 @@ -177,7 +177,7 @@ const ( ### `iota` `iota`は定数を定義するときに使用できる特殊な値で、連続した整数値として取り扱うことができます。説明が少々難しいので、例を見てみましょう。[play](https://play.golang.org/p/EBRDD9qLYlu) ``` go // https://play.golang.org/p/EBRDD9qLYlu @@ -190,7 +190,7 @@ const ( ) ``` 括弧でくくった`const`グループの中であれば、二度目以降の`iota`を省略することもできます。[play](https://play.golang.org/p/1YavGGarLpu) ``` go // https://play.golang.org/p/1YavGGarLpu @@ -203,7 +203,7 @@ const ( ) ``` iotaに対して何かの演算を行った場合、二つ目以降が省略された場合でも、最初に指定した演算と同じものとして扱われます。[play](https://play.golang.org/p/z9I1o5TjvBL) ``` go // https://play.golang.org/p/z9I1o5TjvBL @@ -217,7 +217,7 @@ const ( この、bit shiftと`iota`を用いた定数定義は複数選択可能なフラグの管理などに便利です。 `iota`は`const`を書くごとに0にリセットされます。[play](https://play.golang.org/p/svXJ0UEqZkA) ``` go // https://play.golang.org/p/svXJ0UEqZkA @@ -244,7 +244,9 @@ Go言語では変数を宣言しているのに使用していないという場 リテラルとは、ソースコード中で、数値や文字列を直接に記述した定数のことです。例えば、これまで整数を直接記述した例がいくつか出てきましたが、これは整数リテラルです。整数リテラル、浮動小数点数リテラルはそのまま数値を記述することができます。 文字列を記述するためのリテラルが文字列リテラルで、二つの書き方があります。一つ目は **"..."**(ダブルクォート)を使用する書き方で、改行等を含むことができませんが、"\n"(改行)や"\t"(TAB)などのエスケープシーケンスを使用することができます。二つ目は **`...`**(バッククォート)を使用する書き方で、改行を含むことができますが、エスケープシーケンスは解釈されません。[play](https://play.golang.org/p/9Ef3XKhQKOU) 文字を表現するリテラルとしてRuneリテラルも用意されており、 **'.'**(シングルクォート)を使用します。 ``` go // https://play.golang.org/p/9Ef3XKhQKOU @@ -261,7 +263,12 @@ fmt.Println(bq) 真偽値リテラルは二つの値があり、`true`と`false`(それぞれすべて小文字)をそのまま書くことができます。 ``` go foo := true bar := false ``` Go言語独特のリテラルとして、複合リテラルがあります。複合リテラルは後述する配列やSlice、mapや構造体を初期化するためのリテラルです。型名の後に **{}**(中括弧)を付けるかたちで記述します。中括弧の中には値を列挙するか、index:valueの形で値を記述します。[play](https://play.golang.org/p/HF35Tl0RTJc) ``` go // https://play.golang.org/p/HF35Tl0RTJc @@ -306,7 +313,7 @@ Go言語の変数は必ず型を持っています。変数の型によって格 #### 文字列の長さ: `len()`関数 文字列の長さ(byte数)を取得するには、組み込み関数である`len()`関数が使用できます。[play](https://play.golang.org/p/CwOQ6KZkjKM) ``` go // https://play.golang.org/p/CwOQ6KZkjKM @@ -317,7 +324,7 @@ fmt.Println(len(s)) // 6 ``` 前述の通り、文字列は単なるbyteの列で、`len()`関数はbyte数を返しますので、日本語が含まれる場合は「文字の数」ではない値が返ってきますので注意しましょう。[play](https://play.golang.org/p/Di7sbMSlKDp) ``` go // https://play.golang.org/p/Di7sbMSlKDp @@ -328,7 +335,7 @@ fmt.Println(len(s)) // 15 ``` (Unicode文字列の)文字数を取得したい場合、いったん`rune`のSliceに直してから長さをとります。[play](https://play.golang.org/p/YtmDa4FGsrb) ``` go // https://play.golang.org/p/YtmDa4FGsrb @@ -361,7 +368,7 @@ var arrStr [2]string // 文字列を二個格納できる配列 var arrInt [10]int // 整数を十個格納できる配列 ``` 配列は要素番号(これを「添え字」と呼びます)を使用することで要素にアクセスできます。添え字は最初の要素が0で、その後1, 2, 3...と続きます。[play](https://play.golang.org/p/Fy5THz9O49F) ``` go // https://play.golang.org/p/Fy5THz9O49F @@ -372,9 +379,7 @@ fmt.Println(arr[3]) // qux ``` `:`(コロン)を使って範囲を表現することもできます。この時得られるのがSliceです。Sliceは配列の一部を表現する型です。可変長の配列として扱われることも多く、配列より目にする機会が多いでしょう。`[開始番号:終了番号]`とした時、開始番号で得られる要素は含まれますが、終了番号で得られる要素は含まれないことに注意が必要です。[play](https://play.golang.org/p/ggIKj3ryRhp) ``` go // https://play.golang.org/p/ggIKj3ryRhp @@ -394,7 +399,7 @@ var sliceInt []int #### 要素の追加: `append()`関数 配列は長さが変更できないため、要素の追加をすることはできないのですが、Sliceではできます。その際には、組み込み関数である`append()`を使用します。`append()`は第一引数に任意のSlice、第二引数に追加したい要素を取り、Sliceに要素を追加した新しいSliceを返します。元のSlice(第一引数に与えられたもの)は変更されません。元の配列に追加したい場合には次の様にします。[play](https://play.golang.org/p/hocpa8Y4YiU) ``` go // https://play.golang.org/p/hocpa8Y4YiU @@ -411,9 +416,7 @@ ss = append(ss, "baz") ### Map Mapは配列のようにいくつかの値をまとめた型です。配列とは違う点として、添え字に任意の型が使用できる点、順序を持たない点が上げられます。他の言語では「連想配列」「HashMap」「辞書(dict)」などと呼ばれているものと同様のものです。宣言時には添え字に使う値(キー)と、キーに対応する値を`:`(コロン)で区切りながら宣言します。[play](https://play.golang.org/p/GmG84oktVZU) ``` go // https://play.golang.org/p/GmG84oktVZU @@ -428,9 +431,7 @@ fmt.Println(age["Charlie"]) // 22 ``` 存在しないキーを指定した場合はゼロ値が返ります。単に値を得る場合は第一返値のみで使用できますが、第二返値を受け取ることもできます。第二返値として要求したキーが存在するかどうかが返されます。[play](https://play.golang.org/p/pGjlQu5ms0B) ``` go // https://play.golang.org/p/pGjlQu5ms0B @@ -442,10 +443,11 @@ _, ok1 := age["Alice"] // ok1 == true _, ok2 := age["Bob"] // ok2 == false ``` 要素の追加は代入で行います。[play](https://play.golang.org/p/CnHUgJROIYI) ``` go // https://play.golang.org/p/CnHUgJROIYI age := map[string]int{} age["Dave"] = 30 fmt.Println(age["Dave"]) @@ -455,10 +457,11 @@ fmt.Println(age["Dave"]) #### 要素の削除: `delete()`関数 要素の削除は組み込み関数である`delete()`を使用します。第一引数にMap自体を、第二引数に削除したいキーを与えます。[play](https://play.golang.org/p/PAFfyIuq4v8) ``` go // https://play.golang.org/p/PAFfyIuq4v8 age := map[string]int{ "Alice": 20, "Bob": 18, @@ -487,7 +490,7 @@ func 関数名(引数) 返値の型 { Go言語では関数は返値を複数返すことができます。一つしか返さない場合は括弧でくくらず、型をそのまま記述します。 処理中で返値を返すときは `return`文を使用します。 例として、足し算を行う関数を見てみましょう。[play](https://play.golang.org/p/Ux5wsnjGucT) ``` go // https://play.golang.org/p/Ux5wsnjGucT @@ -498,7 +501,7 @@ func Add(a int, b int) int { ``` この関数はint型の引数を二つ取り、int型の値を一つ返します。このように、同じ型の引数が連続する場合、型宣言をまとめることもできます。 次の関数は先ほどのものと全く等価です。[play](https://play.golang.org/p/07rmFc6BS7j) ``` go // https://play.golang.org/p/07rmFc6BS7j @@ -509,7 +512,7 @@ func Add(a, b int) int { ``` 返値を複数返す場合は、返値を括弧でくくり、カンマ区切りで記述します。このとき、エラーを返したい時には、エラーを **最後の返値にする** のが慣例です。 (エラーではない場合は好きな順番で良い)[play](https://play.golang.org/p/OcTk6d5WQZ3) ``` go // https://play.golang.org/p/OcTk6d5WQZ3 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 5 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -17,6 +17,10 @@ $ go version `go version go1.12 darwin/amd64`(macOS、Go1.12の場合)のように表示されればOKです。 ### 環境変数の設定 環境変数`GO111MODULE`に`on`を設定してください。Linux/macOSでは、`export GO111MODULE=on`と実行する(現在のセッションに適用する)か、.bashrcや.zshrcなどに記載する(永続的に適用する)ことで設定できます。 ### エディタの用意 Go言語はお好みのエディタで開発を行うことができます。日常的に使用しているエディタがあればそちらをそのまま使用してください。 @@ -25,11 +29,7 @@ Go言語はお好みのエディタで開発を行うことができます。日 * emacs: `go-mode`をインストールしてください。 * vim: `vim-go`が有名なようです。 * Visual Studio Code: `vscode-go`プラグインをインストールしてください。 * JetBrains(IntelliJ)ユーザ: GoLandが人気のようです(ライセンスについては各自ご確認ください。 ## プログラムの実行 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,6 +27,10 @@ Go言語はお好みのエディタで開発を行うことができます。日 * Visual Studio Code: `vscode-go`プラグインをインストールしてください。 * JetBrains(IntelliJ)ユーザ: GoLandが人気のようです(ライセンスについては各自ご確認ください) ### 環境変数の設定 環境変数`GO111MODULE`に`on`を設定してください。Linux/macOSであれば、`export GO111MODULE=on`として設定します。 ## プログラムの実行 準備ができたら、早速Go言語のプログラムを実行してみましょう! -
nasa9084 revised this gist
Jul 16, 2019 . No changes.There are no files selected for viewing
-
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -77,7 +77,7 @@ Go言語のプログラムは「パッケージ」という単位で開発をし 実は`main`パッケージはちょっと特殊なパッケージで、「このパッケージは実行するためのパッケージである」ということを示します。`go run`や`go build`でビルドされるのは`main`パッケージと決まっています。逆に、他のパッケージから読み込まれるためのパッケージは`main`という名前にしてはいけません。 他のパッケージを読み込む際は`import`に`"`(ダブルクォート)で括ったパッケージ名を記述します。標準パッケージの場合はそのままパッケージ名を記述します(例: `"fmt"`)。[GitHub](https://github.com)上にあるパッケージを使用したい場合は、github.comから始まるパスを記述します(例: `"github.com/nasa9084/go-totp"`)。標準パッケージの一覧と詳細なドキュメントは[golang.org/pkg](https://golang.org/pkg)で見ることができます。 パッケージ名は文字から始まり、文字と数字、`_`(アンダーバー)を使って自由に名前を付けることができます(誰もやりませんが、日本語で名前を付けることもできます)。あまり長くない名前で、`_`や数字を使っていない名前が多いです。 一つのディレクトリには一つのパッケージ(ちょっと例外もありますが)しか入れることはできません。ディレクトリ内の.goファイルはすべて同じパッケージ名を持つようにしてください。 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -77,7 +77,7 @@ Go言語のプログラムは「パッケージ」という単位で開発をし 実は`main`パッケージはちょっと特殊なパッケージで、「このパッケージは実行するためのパッケージである」ということを示します。`go run`や`go build`でビルドされるのは`main`パッケージと決まっています。逆に、他のパッケージから読み込まれるためのパッケージは`main`という名前にしてはいけません。 他のパッケージを読み込む際は`import`に`"`(ダブルクォート)で括ったパッケージ名を記述します。標準パッケージの場合はそのままパッケージ名を記述します(例: `"fmt"`)。GitHub上にあるパッケージを使用したい場合は、github.comから始まるパスを記述します(例: `"github.com/nasa9084/go-totp"`)。標準パッケージの一覧と詳細なドキュメントは golang.org/pkg で見ることができます。 パッケージ名は文字から始まり、文字と数字、`_`(アンダーバー)を使って自由に名前を付けることができます(誰もやりませんが、日本語で名前を付けることもできます)。あまり長くない名前で、`_`や数字を使っていない名前が多いです。 一つのディレクトリには一つのパッケージ(ちょっと例外もありますが)しか入れることはできません。ディレクトリ内の.goファイルはすべて同じパッケージ名を持つようにしてください。 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -77,7 +77,7 @@ Go言語のプログラムは「パッケージ」という単位で開発をし 実は`main`パッケージはちょっと特殊なパッケージで、「このパッケージは実行するためのパッケージである」ということを示します。`go run`や`go build`でビルドされるのは`main`パッケージと決まっています。逆に、他のパッケージから読み込まれるためのパッケージは`main`という名前にしてはいけません。 他のパッケージを読み込む際は`import`に`"`(ダブルクォート)で括ったパッケージ名を記述します。標準パッケージの場合はそのままパッケージ名を記述します(例: `"fmt"`)。GitHub上にあるパッケージを使用したい場合は、github.comから始まるパスを記述します(例: `"github.com/nasa9084/go-totp"`)。標準パッケージの一覧と詳細なドキュメントは[golang.org/pkg]で見ることができます。 パッケージ名は文字から始まり、文字と数字、`_`(アンダーバー)を使って自由に名前を付けることができます(誰もやりませんが、日本語で名前を付けることもできます)。あまり長くない名前で、`_`や数字を使っていない名前が多いです。 一つのディレクトリには一つのパッケージ(ちょっと例外もありますが)しか入れることはできません。ディレクトリ内の.goファイルはすべて同じパッケージ名を持つようにしてください。 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -77,6 +77,8 @@ Go言語のプログラムは「パッケージ」という単位で開発をし 実は`main`パッケージはちょっと特殊なパッケージで、「このパッケージは実行するためのパッケージである」ということを示します。`go run`や`go build`でビルドされるのは`main`パッケージと決まっています。逆に、他のパッケージから読み込まれるためのパッケージは`main`という名前にしてはいけません。 他のパッケージを読み込む際は`import`に`"`(ダブルクォート)で括ったパッケージ名を記述します。標準パッケージの場合はそのままパッケージ名を記述します(例: `"fmt"`)。GitHub上にあるパッケージを使用したい場合は、github.comから始まるパスを記述します(例: `"github.com/nasa9084/go-totp"`)。 パッケージ名は文字から始まり、文字と数字、`_`(アンダーバー)を使って自由に名前を付けることができます(誰もやりませんが、日本語で名前を付けることもできます)。あまり長くない名前で、`_`や数字を使っていない名前が多いです。 一つのディレクトリには一つのパッケージ(ちょっと例外もありますが)しか入れることはできません。ディレクトリ内の.goファイルはすべて同じパッケージ名を持つようにしてください。 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -997,7 +997,9 @@ Buzz * 1からNまでについて表示する * Nはコマンドライン引数からとる Hint: * コマンドライン引数は[`flag.Arg()`または`flag.Args()`](https://golang.org/pkg/flag/#Arg)を使用して得ることができます。 * 文字列から数値への変換は[`strconv.Atoi()`](https://golang.org/pkg/strconv/#Atoi)を使用します。 ## goroutineを用いた並行処理 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 7 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -992,6 +992,13 @@ Fizz Buzz ``` 今回は次の様な仕様で実装してみましょう。 * 1からNまでについて表示する * Nはコマンドライン引数からとる Hint: コマンドライン引数は[`flag.Arg()`または`flag.Args()`](https://golang.org/pkg/flag/#Arg)を使用して得ることができます。 ## goroutineを用いた並行処理 Go言語の非常に大きな特徴として、言語の仕様レベルで並行処理をサポートしていることが挙げられます。他の言語では使うこと自体が少々面倒なことも多い並行処理が、Go言語ではとても簡単に並行処理を使ったプログラムを書くことができます。 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 29 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -962,7 +962,35 @@ Go言語でのエラー処理方法は大きく分けて二つあります。 ### FizzBuzz Goを用いたプログラミングの練習として、**FizzBuzz**を実装してみましょう。FizzBuzzはプログラミングの練習でよく使用される課題の一つで、次のようななものです。 * 順番に数字を表示していく(入力した数字を対象とする場合もある) * 対象の数字が3の倍数なら **Fizz** を、対象の数字が5の倍数なら **Buzz** を、3と5両方の倍数なら **FizzBuzz** を、それ以外の数字なら数字をそのまま、表示する 1から20まで表示する例: ``` 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizBuzz 16 17 Fizz 19 Buzz ``` ## goroutineを用いた並行処理 -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -958,15 +958,19 @@ func 関数名() { ### エラー処理 Go言語でのエラー処理方法は大きく分けて二つあります。 ### FizzBuzz ## goroutineを用いた並行処理 Go言語の非常に大きな特徴として、言語の仕様レベルで並行処理をサポートしていることが挙げられます。他の言語では使うこと自体が少々面倒なことも多い並行処理が、Go言語ではとても簡単に並行処理を使ったプログラムを書くことができます。 ### goroutine Go言語で並行処理をするには、goroutine(ごるーちん/ごーるーちん)を使用します。使用方法は至って簡単で、次のように関数呼び出しの前に`go`と付けるだけです。 ``` go go 関数() -
nasa9084 revised this gist
Jul 16, 2019 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -242,6 +242,7 @@ Go言語では変数を宣言しているのに使用していないという場 ``` go // https://play.golang.org/p/9Ef3XKhQKOU dq := "Hello\nWorld" fmt.Println(dq) bq := `Hello\nWorld`
NewerOlder