それが僕には楽しかったんです。

僕と MySQL と時々 MariaDB

PHPerがいくGolang入門 A Tour of Go Basics, Packages, variables, and functions

はじめに

どうも、2018/12/19という未来からきたけんつです。
この記事は、Muroran Institute of Technology Advent Calendar 2018 19日目の記事です。

なんかクリスマスも近いのでGolang入門やろうと思います。
今回は基本文法周り攻めれたらなと思っています。

A Tour Of Goを見ながら進めていきます。
基本的な四則演算等は省略します。

環境

Ubuntu 16.04
go version go1.6.2 linux/amd64

Hello,World

goはpackage単位でプログラムを組むらしい。
もっと言うならば、mainパッケージのmain関数から実行していく。

package main;

import "fmt";

func mainsub() {
    fmt.Println("hello,world");
}


こんな感じで。
セミコロンは省略できるが個人的に書いていきたいから書く。

ちなみに関数名をmain以外にすると次のように怒られる。

# command-line-arguments
runtime.main: call to external function main.main
runtime.main: main.main: not defined
runtime.main: undefined: main.main

package.関数で探しているっぽい。

上記のファイルを hello.go としたとき、以下の様に走らせると標準出力がでてくる。

$ go run hello.go 
hello,world
||< 

そして、この先頭でインポートしているパッケージ群にフォーマットI/Oに必要な関数群があるので
基本的にこれはインポートすることになる。

* 複数パッケージのインポートとパッケージ内の関数参照

Hello,worldの時点で色々と個人的に謎が深まったので一番気になった、パッケージの複数インポートとパッケージ内の関数参照についてまとめていく。


** 複数のパッケージインポート

次の様に出来る 
>|go|
import "fmt";
import "math";

次の様にまとめることも出来る。

import (
    "fmt"
    "math"
);

パッケージ内の参照

次の様に、パッケージ名.メンバで参照できる(メンバと言って良いのかわからないけど)

package main;


import (
    "fmt"
    "math"
);


func main() {
    fmt.Println(math.Pi);
}
$ go run multi_package.go 
3.141592653589793

関数

次に関数について、触れていく。
関数は例によって0個以上の引数を取ることができる。
そして戻り値を返すこともできる。

何やら型でintが存在するようなので早速書いてみる。

package main;

import "fmt";

func add(x int, y int) int {
    return x + y;
}

func main() {
    fmt.Println(add(1, 3));
}
$ go run functions.go 
4

コードを見てもらうとわかるように、引数名の後に型名をおいているScalaのように。
戻り値の型も宣言できている。returnも使える。

関数宣言は呼び出しより後ろにあってもエラーにならずコールされる。

package main;

import "fmt";

/*func add(x int, y int) int {
    return x + y;
}*/

func main() {
    fmt.Println(add(1, 3));
}
func add(x int, y int) int {
    return x + y;
}
$ go run functions.go 
4

また、型が同じなら次のように省略できる。

func add(x, y int) int {
    return x + y;
}

これはあまり好きではないので、これからは省略できても一個一個型を書いていく。

複数の結果を返す

これは驚きの機能で複数の結果をreturnすることができる。
すごく簡単で、以下のようにする。

package main;

import "fmt";

func main() {
    fmt.Println(add(1, 3));

    a, b := swap("hello", "world");
    fmt.Println(a, b);
}

func add(x, y int) int {
    return x + y;
}

func swap(a string, b string) (string, string) {
    return b, a;
}
$ go run functions.go 
4
world hello

これ便利。

名前付きreturn

これも地味に便利だとおもった。
次のコードの様に、戻り値に名前を付けて返すことが出来る。

package main;

import "fmt";

func main() {
    fmt.Println(split(17));
}

func split(sum int) (x int, y int) {
    x = sum * 4 - 9;
    y = sum - x;
    return;
}
$ go run name_return.go 
59 -42

変数宣言

var を使って変数を宣言する

package main;

import "fmt";

var c, python, java bool;

func main() {
    var i int;
    fmt.Println(i, c, python, java);
}
$ go run variables.go 
0 false false false

構文としては 「var 変数名 型名;」となっている。
何も変数に代入しない場合はデフォルトの値が設定される。

変数初期化

初期化は初期化子を使うことが宣言時に出来る。
これによって初期化された場合、型名は省略できる。

package main;

import "fmt";

var c, python, java bool = true, false, true;

func main() {
    var i = 10;
    fmt.Println(i, c, python, java);
}
$ go run variables.go 
10 true false true

短縮宣言

varを使う代わりに、:=を使い暗黙的な型宣言を行うことができる。
しかし、この構文は関数の外で使うことができない。

package main;

import "fmt";

var c, python, java bool = true, false, true;

func main() {
    var i = 10;
    fmt.Println(i, c, python, java);

    scala, php := true, false;
    fmt.Println(scala, php);
}
$ go run variables.go 
10 true false true
true false

基本型は次の通り

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
     // Unicode のコードポイントを表す

float32 float64

complex64 complex128

型変換

キャストに近いことができる。
利用方法は簡単で「形名(変数or値)」とするだけ。

おわりに

楽しい。