simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Goはローカルで通信確認できる?

■前置き1

Go 環境整って Hello World 動きます。
言語の目的がマルチコアのネットワークブログラムなんだから、数行でサーバーとして機能するんだよね?
どういう書式か確認させてもらおう

■前置き2

先に書式を学んで行け、馬鹿野郎
とドキュメントに怒られたので、A Tour of Go を体験することにしました。

関数定義、変数定義は型を変数名の後ろに持ってくることでいけます。(変数名から入れるって直感的でいいですね)
初期化時に型が確定している場合は、型を宣言しなくてよくなります。(ビルドに時間かかりそうな書式だな…)
未初期化変数は0
明示的な型変換が必要 float64 a = int 0 みたいなことができない
const が使える(やった)

書式を習っていて驚いたこと

  • 関数の戻り値は一つじゃなくてもいい(柔軟ですね!)
  • naked return という新しい概念が使える split(sum int) (x, y int) という、引数の後ろに引数のようなものを記述してコンパイルが通り、そしてこの二つ目の定義が戻り値として戻ってくる(読めねぇよ!)
  • 標準の型で複素数の complex がある(やるな!)
  • defer というキーワードにより、関数を抜ける時に実行させられるLIFO(last-in-first-out)
  • ポインタが使えるがポインタ演算はない(ん?)
  • 構造体のポインタからメンバアクセスが . でできる(これでポインタと参照切り替え時にコード書き換えなくていいね)
  • 配列がスライス可能、スライスは参照
  • null は nil らしい
  • foreach に当たる構文は range で優しいことに要素のインデックスも渡してくれる
  • while に相当するのは for {}
  • for {} にラベルを付けると swich の中からでも for {} を抜けることができる(この書式を待ってました!)
  • map のキー確認に contentskey なる関数が不要、複数戻り値の2番目に true, false が返ってくる(これはうれしい)
  • 関数に関数オブジェクトを渡せる
  • クロージャー?という概念で、関数の戻り値が内部生成関数のようでいて、その内部生成関数の戻り値、おおもとの関数のローカル変数を内部関数が利用できる点で、そのローカル変数にバインドできるというもの

ここでいう関数内の内部関数がクロージャだとか(アニメーションは頭の中でできるけど、学習コスト高そうなのであんま使いたくないな)

クロージャーのエクササイズで私が書いた答え(なんか汚いな)

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	p := 0
	s := p
	return func() int {
		d := p
		if p == 0 {
			p = 1
		}
		p = p + s
		s = d
		return d
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

Slice の Exercise では次のコードを答えに書きました

package main

import "golang.org/x/tour/pic"

func Pic(dx, dy int) [][]uint8 {
	img := make([][]uint8, dy)
	for y := 0; y < dy; y++ {
		img[y] = make([]uint8, dx)
		for x := 0; x < dx; x++ {
			img[y][x] = uint8(x*y)
		}
	}
	return img
}

func main() {
	pic.Show(Pic)
}
||< 

Exercise: Maps の私の答えは次の通り

>|go|
package main

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	m := make(map[string]int)
	for _, v := range strings.Fields(s) {
		if e, ok := m[v]; ok {
			m[v] = e + 1
		} else {
			m[v] = 1
		}
	}
	return m
}

func main() {
	wc.Test(WordCount)
}

■前置き3

前置きの A Tour of Go による書式習得時間が長い…
サーバーとして起動するには?
net パッケージを import して port listen すればよいとのこと

参考にした記事
golang socket server & client ping-pong demo
go server-clientアプリケーションの実装

同時接続のところで、さっそく goroutine (ゴルーチン) 使うコード出てきちゃった、また tour of Go やり直します。
go って書くと軽量マルチコアスレッド処理が起動して チャネル( Channel )型 で計算が完了するのをブロックして待つとのことです。

あ、フィボナッチはこう書くのか、そしてバッファーチャネルやクローズを学ぶ

package main

import (
	"fmt"
)

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	for i := range c {
		fmt.Println(i)
	}
}

Go 言語はプログラマが何年も、何十年も悔しい思いをして
無駄に煩雑に書いてきたロジックを、構文を使ってすっきりと書けるようにしてくれる小技が多く感じられる
超好きになった!

■本題

先ほど紹介した記事
golang socket server & client ping-pong demo

こちらを go build して試すことでローカルでの通信確認できました。
長らくコードの書式を頭に叩き込みましたので、コードの流れが追えるようになっています。

これにて目的達成!