はじめに
こんばんは。 今年も早くも10ヶ月たって、全く成長してない僕です。
今年のはじめに決めた目標はブレブレになってしまって、どれもこれも中途半端という不甲斐ない結果になっております。
まぁ嘆いてもしょうがないので、今月から気を引き締めて、またやっていこうと思います。
とりあえず今年10月から来年も踏まえて、Go、Python、Javascriptの3つを重点的に勉強しようと思ってます。
比率的には
Go: 4 Javascript: 4 Python: 2
といった比率で勉強しようと思ってます。
なんでこの比率かというと、
Goは、もともと勉強したいというのがあったのですが、知人からGoの案件を紹介してもらったことがきっかけでした。その時は実務経験も勉強もしてない状態だったのでスキル的にミスマッチだったので断ったのですが、せっかくのお誘いを自分のスキル不足で台無しにしてしまうのが悔しかったので、やろうと思いました。
Javascriptは、今年の目標の一つで、フロントエンド側の知見を貯めるというのに続いています。何回かReactやVue.jsの勉強やりましたが、実践で使えるほどの知見は全然溜まってないので、もう少し踏み込んで勉強をしていこうと思っています。FWはReactに絞って勉強しようと思ってます。
Pythonに関しては、唯一成長したというか、調べつつ書けるようになってきている実感があるので、ある程度勉強は続けていこうと思いこの比率です。
あとはSwiftも個人的にやってた時期があるので、どうにか滑り込ませたいなと思ってますが、時間的に厳しいかも。。。
とりあえず今回はGo言語の勉強ですね。
大昔にTour of Goやったくらいなので、さっぱり忘れてます。
さっそくいきます。
やってみた
定番のHello World
package main import "fmt" func main() { fmt.Println("Hello World") }
go build goファイルで、ビルドされたバイナリが作成されて、そのバイナリを実行すれば、Hello Worldが表示される
$ go build hello.go $ ./hello Hello World $ ls -la total 3920 drwxr-xr-x 4 kojirock staff 128 10 3 00:07 . drwxr-xr-x 21 kojirock staff 672 10 2 23:54 .. -rwxr-xr-x 1 kojirock staff 1999368 10 3 00:07 hello -rw-r--r-- 1 kojirock staff 72 10 3 00:01 hello.go
go run goファイル名で、ビルドと実行が同時に行われるけど、対象のバイナリは作られない
$ go run hello.go Hello World $ ls -la total 8 drwxr-xr-x 3 kojirock staff 96 10 3 00:03 . drwxr-xr-x 21 kojirock staff 672 10 2 23:54 .. -rw-r--r-- 1 kojirock staff 72 10 3 00:01 hello.go
制御構文
- 繰り返し処理はforのみ、while, foreach, do whileなどはない。でもforのみで再現できる。
// 普通のfor for i:=0; i < 5; i++ { fmt.Println(i) } // while count := 0 for count < 10 { fmt.Println(count) count++ } // foreach的なやつ data_list := map[string]int{ "aaa": 10, "bbb": 20, "ccc": 30, } for key, value := range data_list { fmt.Println("key => ", key, " value => ", value) }
衝撃だったけど、forしかないことで逆にシンプルだと思った。
break
continue
は通常通り使えるとのこと。
関数とか変数とか
- 頭文字が小文字のメンバは、同パッケージ内からのみアクセス可能
- 頭文字が大文字のメンバは、別パッケージからもアクセス可能
- 基本的に変数はvar, 関数はfuncで定義
- 変数は型推論があるので、型の省略も可能
- ローカル変数に関しては、型を指定できず、宣言も
:=
で行う - const定義も可能で、かつ、型を持たない定数が可能。また、関数内でも定義できる。
- iotaという列挙型みたいなものをconstでは指定できる。
テストのために自分で作成したローカルパッケージを作成してimportする
test_01.go
package package_test // All package_testの全メソッドを呼ぶ func All() { aaa() bbb() ccc() ddd() println(bbbvar) println(dddconst01) } func aaa() { println("aaa") }
test_02.go
package package_test var bbbvar = 100 func bbb() { println("bbb") }
test_03.go
package package_test func ccc() { cccvar := 200 println("ccc") println(cccvar) }
test_04.go
package package_test const dddconst01 = "dddconst01" func ddd() { const dddconst02 = 2 println(dddconst02) println("ddd") }
hello.go
package main import "./package_test" const ( Red = iota Blue Yellow ) func main() { package_test.All() println(Red) println(Blue) println(Yellow) }
$ go run hello.go aaa bbb ccc 200 2 ddd 100 dddconst01 0 1 2
いろんな型
配列型
固定長の配列を作成する。
// 定義1 var data_array [3]int // 定義2(初期値を指定できる) var data_array = [3]int{10, 20, 30} // 定義3(初期値を指定すると、長さの宣言は...で省略できる) var data_array = [...]int{10, 20, 30} // 定義4(indexを指定して初期値を設定できる) var data_array = [...]int{0: 10, 1: 20, 2: 30}
スライス型
可変長の配列を作成する。
// 定義1 var data_array []int // 定義2(初期値を指定できる) var data_array = []int{10, 20} // 追加方法はappend() var data_array = []int{10, 20} data_array = append(data_array, 30) println(data_array[2]) // => 30
マップ型
var data_array = map[string]int{"aaa": 10, "bbb": 20} data_array["ccc"] = 30 // 代入は簡単
型宣言(type)
独自の型を作成できる。
reflectパッケージの TypeOf()
で指定のものがなんの型がわかる。
package main import "fmt" import "reflect" type TestType int var param1 TestType = 100 var param2 int = 200 func main() { fmt.Println(param1) fmt.Println(param2) fmt.Println(reflect.TypeOf(param1)) fmt.Println(reflect.TypeOf(param2)) }
$ go run type.go 100 200 main.TestType int
学生時代C言語やってたときにこんな事やった記憶があるような気がする。
構造体(Struct)
Goはクラスがないから構造体。めちゃ懐かしい。
- math/randパッケージを使用して乱数を生成している
- strconvパッケージを使用して、数値から文字列へのキャストをこなっている
package main import ( "fmt" "math/rand" "strconv" "time" ) type Player struct { life int attack int luck int } func (p *Player) is_die() bool { return p.life == 0 } func (p *Player) damege(point int) { p.life -= point if p.life < 0 { p.life = 0 } } type Enemy struct { life int attack int luck int } func (e *Enemy) is_die() bool { return e.life == 0 } func (e *Enemy) damege(point int) { e.life -= point if e.life < 0 { e.life = 0 } } func main() { var player Player var enemy Enemy player.life = 10 player.attack = 1 player.luck = 5 enemy.life = 10 enemy.attack = 1 enemy.luck = 5 // 無限ループはこの書き方 for { player_attack_offet := 0 enemy_attack_offet := 0 rand.Seed(time.Now().UnixNano()) if player.luck >= rand.Intn(10) { // 会心の一撃出す player_attack_offet++ } if enemy.luck >= rand.Intn(10) { // 痛恨の一撃出す enemy_attack_offet++ } enemy.damege(player.attack + player_attack_offet) fmt.Println("プレイヤーの攻撃!敵に" + strconv.Itoa(player.attack+player_attack_offet) + "のダメージを与えた!") player.damege(enemy.attack + enemy_attack_offet) fmt.Println("敵の攻撃!プレイヤーに" + strconv.Itoa(enemy.attack+enemy_attack_offet) + "のダメージを与えた!") if player.is_die() == true { fmt.Println("敵の勝ち!") break } else if enemy.is_die() == true { fmt.Println("プレイヤーの勝ち!") break } } }
$ go run struct.go プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの勝ち!
ダラダラと長くなってしまったけど、こんな感じなのかな?
ポインタ型
C言語でお馴染みのポインタ。確か僕が挫折したのがポインタ。
ただ、ロジックの見通しよくするためには、必要だし、苦手意識は克服しなければ。
func main() { var player Player var enemy Enemy player.life = 10 player.attack = 1 player.luck = 5 enemy.life = 10 enemy.attack = 1 enemy.luck = 5 // 無限ループはこの書き方 for { battle(&player, &enemy) if player.is_die() == true { fmt.Println("敵の勝ち!") break } else if enemy.is_die() == true { fmt.Println("プレイヤーの勝ち!") break } } } func battle(player *Player, enemy *Enemy) { player_attack_offet := 0 enemy_attack_offet := 0 rand.Seed(time.Now().UnixNano()) if player.luck >= rand.Intn(10) { // 会心の一撃出す player_attack_offet++ } if enemy.luck >= rand.Intn(10) { // 痛恨の一撃出す enemy_attack_offet++ } enemy.damege(player.attack + player_attack_offet) fmt.Println("プレイヤーの攻撃!敵に" + strconv.Itoa(player.attack+player_attack_offet) + "のダメージを与えた!") player.damege(enemy.attack + enemy_attack_offet) fmt.Println("敵の攻撃!プレイヤーに" + strconv.Itoa(enemy.attack+enemy_attack_offet) + "のダメージを与えた!") }
$ go run struct.go プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに1のダメージを与えた! プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! プレイヤーの攻撃!敵に2のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! プレイヤーの攻撃!敵に1のダメージを与えた! 敵の攻撃!プレイヤーに2のダメージを与えた! 敵の勝ち!
おわりに
とりあえず今日はここまでです。
やってみて思ったけど、すごくシンプルで覚えることも少なそうだけど、シンプルだからこそ、設計力が求められそうな感じだと思いました。
でも、Go言語でガッツリwebサービス作るっていうよりはAPI的な立ち位置で使ってるケースが多いからそこまで大規模に使うものでもないのかもしれません。
でもGoのフレームワークもあるみたいだし、せっかくだからwebサービス作る方向で勉強してみようとおもいます。
おすすめの本などあれば教えてください。
そういえば、最近やっとsublimeからvscodeに乗り換えたんですけど、すごくいいですね。同じElectronで作られてるAtomとはえらい違いです。
php or jsはphpstorm
pythonはspyder
それ意外のものに関してはvscode
って感じで定着しそうです(もはやpythonもvscodeになりそう)
おやすみなさい。