お首が長いのよお首が長いのよ

チラシの裏よりお届けするソフトウェアエンジニアとして成長したい人のためのブログ

2018-11-25

Go言語の環境整備と基本文法を学んだ

環境準備

VSCode上で適当なワークスペースを用意した。 今回は「/Users/{わたし}/Documents/Projects/golang_introduction としてディレクトリを用意した。

golangのインストール

macOSを使用しているので、homebrewを使ってインストールする

bash
1$ brew info go
2go: stable 1.11.1 (bottled), HEAD
3Open source programming language to build simple/reliable/efficient software
4https://golang.org
5Not installed
6From: /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/go.rb
7==> Requirements
8Required: macOS >= 10.109==> Options
10--HEAD
11    Install HEAD version
12==> Caveats
13A valid GOPATH is required to use the `go get` command.
14If $GOPATH is not specified, $HOME/go will be used by default:
15  https://golang.org/doc/code.html#GOPATH
16
17You may wish to add the GOROOT-based install location to your PATH:
18  export PATH=$PATH:/usr/local/opt/go/libexec/bin
19==> Analytics
20install: 91,529 (30d), 265,569 (90d), 943,528 (365d)
21install_on_request: 64,960 (30d), 187,842 (90d), 594,605 (365d)
22build_error: 0 (30d)
23

brewで入る最新は1.11.2だった。1.11自体が2018/08リリースと割と新しいものだったのでこのままインストール

bash
1$ brew install go
2

VSCodeについては .goファイルを作成してしまえばVSCodeからエクステンションのインストール案内が出るので そのままインストール。

入門

GOPATHの設定

bash
1export GOPATH=/Users/{わたし}/Documents/Project/golang_introduction/
2

golangはワークスペースプロジェクト単位で開発する。 基本的にコマンドやビルドを行う際にGOPATHを頼りに行うイメージかな? ディレクトリ(=プロジェクト)毎にGOPATHを設定したい等のニーズに答えるためにgoenvといったツールも用意されている。

Hello world

golang
1package main
2
3import(
4        "fmt"
5)
6
7func main() {
8        fmt.Println("Hello world!")
9}
10

実行

bash
1$go run hello_world.go
2Hello world!
3

疑問:importしている「fmt」って何?

フォーマットから取ったパッケージ。 基本的にはC言語でいう「print」や 「scan」にあたる関数を提供する。

コメント

golang
1// 1行コメント
2
3/*
4複数行コメント
5
6*/
7

import

golang
1import (
2    "fmt"
3    "math"
4)
5

こっちも可

golang
1import "fmt"
2import "math"
3

ただし、こちらは推奨されないらしい。

exported name

golangでは名前の先頭が大文字のものは、外部から利用できる。

golang
1package main
2
3import (
4    "fmt"
5)
6
7func main() {
8    fmt.Println("Hello world!")
9}
10

この場合だとPrintlnがそれにあたる。

変数の定義

var で宣言して初期化する事が出来る。 型を明示的に指定する場合、intなどの型名は変数名の後に指定する。

golang
1var x int = 10
2var y int = 20
3
4//こっちも可能
5var x,y int = 10,20
6

文字列の場合はダブルクォーテーションで括る

golang
1var foo string = "bar"
2fmt.Println(foo) //bar
3

また、上記より短い宣言もできる

golang
1var foo = "bar"
2

varという初期化子をつけて変数に値を代入した場合、型を省略できる。 省略された変数の型は、代入された値によって自動的に割り当てられる。 (型推論)

他に、:=を使って宣言する方法がある。

golang
1foo2 := "bar"
2
3var num1 = 10
4num2 := 100
5

:= を使って宣言するのは型などをいい感じに認識してもらう「暗黙的宣言」という。 「暗黙的宣言」の場合は関数スコープ内でのみ利用が可能である。 つまり、関数の外では:=を使った暗黙的宣言はできない。

定数

最近のJavaScriptのように「const」をつけることで定数が宣言できる

golang
1const message = "hello?"
2
3message = "Hi!" //エラー
4

定数(const)は、文字、文字列、boolean、数値でのみ使える。 定数の場合は := を使った宣言は利用できない。

ゼロ値

変数宣言時、何も値を指定しない場合、ゼロ値(zero value)が与えられる。 ゼロ値といっても数字の0(ゼロ)を入れるだけでなく、変数型によって異なる

  • 数値型の場合(int/float) ... 0
  • bool型の場合... false
  • string型の場合... "" (空文字列)

この辺りはnull判定のときなどに活用できそうだ。

関数,function

よくある感じでOK。引数を指定する場合は上述の通り型が後。

golang
1//func( [引数名] [型]) [戻り値の型] {}
2
3func main() {
4    calc(1,2) //3
5}
6
7func calc(a int, b int){
8    var c int
9    c = a + b
10    fmt.Println(c)
11}
12

マルチプルリザルト

golangの特徴で、関数が複数の戻り値を返す事ができる。

golang
1func main() {
2    a, b := swap("hello", "world")
3    fmt.Println(a, b)  // hello__x world~~y
4}
5
6func swap(x, y string) (string, string){
7    x += "__x"
8    y += "~~y"
9    return x, y
10}
11

if文

条件式は丸括弧()で括らない。

golang
1func main() {
2    evaluation("test","test") //a==b
3    evaluation("test","hoge") //a!=b
4}
5
6func evaluation(a string, b string){
7
8    if a==b {
9        fmt.Println("a==b")
10    }else{
11        fmt.Println("a!=b")
12    }
13}
14

for文

よくあるfor文はこんな感じ。他の言語のように丸かっこ()で括る必要はない点に注意

golang
1for i :=0; i < count; i++ {
2    fmt.Println(i)
3}
4
5//0
6//1
7//2
8//3
9//4
10//5
11//6
12//7
13//8
14//9
15

他の言語でいうwhileっぽいやり方も出来る

golang
1var i = 0
2for i < count {
3    i++ 
4    fmt.Println(i)
5}
6
7//0
8//1
9//2
10//3
11//4
12//5
13//6
14//7
15//8
16//9
17

無限ループ

golang
1for {
2  fmt.Println("forever!")
3}
4

Array, 配列

配列は固定長。長さを変える事ができない。

golang
1func main() {
2    var a [2]string
3    a[0] = "Captain"
4    a[1] = "America"
5    fmt.Println(a[0], a[1]) // Captain America
6    fmt.Println(a) // [Captain America]
7
8    primes := [6]int{2, 3, 5, 7, 11, 13}
9    fmt.Println(primes) //[2 3 5 6 11 13]
10}
11

個人的には変数そのものを出力するとカンマ区切りでなく スペース区切りになる点が気になる

スライス

こっちは可変長の配列だと思っていいらしい

golang
1func main() {
2
3    names := [4]string{
4        "John",
5        "Paul",
6        "George",
7        "Ringo",
8    }
9    fmt.Println(names) // [Joh Paul George Ringo]
10
11    a := names[0:2]
12    b := names[1:3]
13    fmt.Println(a, b) // [John Paul]  [ Paul George]  ...①
14
15    b[0] = "XXX"
16    fmt.Println(a, b)  // [John XXX] [ XXX George]  ...②
17    fmt.Println(names) // [John XXX George Ringo]
18}
19

他の言語もそうなのかもしれないけど、スライスは以下のような形で切り取って扱う事が出来る

①では、最初に0〜2を指定している。つまり、以下の範囲を指定したことになる。 つまり、John とPaulが出力対象

次に、1〜3を指定している。つまり、以下の範囲で、PaulとGeorgeが取扱の対象。

スライスは配列への参照のようなもの (らしい)

スライスは配列への参照のようなものです。 スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。 スライスの要素を変更すると、その元となる配列の対応する要素が変更されます。 同じ元となる配列を共有している他のスライスは、それらの変更が反映されます。

②で取り扱っているのがまさにその部分。 一度スライスを他の変数に代入し、他の編集の値を書き換えたとしても、大元のスライスにもその変更が反映される。

/以上

よかったらシェアしてください!