Open2

Go学習メモ(知見がまとまったら記事化します)

skonbskonb

Goで変数名の後ろに型名を書く理由

(https://go.dev/blog/declaration-syntax)

C言語

C言語では型(type)が左,式(expression)が右

int x;
int main(int argc, char *argv[]) { /* ... */ }

C言語流の記法は型が少ないうちはいいが,型が複雑になってくると難読化する

//int型引数を2つ取る関数型ポインタ
int (*fp)(int a, int b);

//fpの引数にint (*fp)(a, b) を渡す場合...
int (*fp)(int (*ff)(int x, int y), int b).    //???

//関数ポインタを返す場合(もはや何が帰ってくるかわからない)
int (*(*fp)(int (*)(int, int), int))(int, int) 

go

//変数
x int
p *int
a [3]int
//関数
func main(argc int, argv []string) int

とにかく「左から右」に読めるというのが利点とのこと.
型が複雑になっても読みやすい.

//最終的に帰ってくる型がわかりやすい
f func(func(int,int) int, int) int       //intが帰ってくる
f func(func(int,int) int, int) func(int, int) int //関数ポインタが帰ってくる

ただし,ポインタの"*"(アスタリスク)だけはCと同様のルールになっているようです.

var p *int
x = *p
skonbskonb

Golangの面白いと思った書き方

変数

//定数はconstで宣言.セイウチ演算子は使えない.
const World = "世界"
//変数を同時に複数代入できる(「初期化子initializerを与える」と言う)
var i, j int = 1, 2
//型は省略できる
var c, python, java = true, false, "no!"
//セイウチ演算子で暗黙的な型宣言ができる.(関数内のみ)
c, python, java := true, false, "no!"
//Goでは暗黙的な型変換は一切存在しない
var x, y int = 3, 4
fmt.Println(math.Sqrt(float64(x*x + y*y))) 
//結果 : 5
//fmt.Println(math.Sqrt(x*x + y*y))
//結果 : cannot use x * x + y * y (type int) as type float64 in argument to math.Sqrt

Function

// 引数の型が同じ場合はまとめて書ける
func add(x, y int) int {
	return x + y
}
//返り値を複数返せる(errorを返す場合などでありがち)
func swap(x, y string) (string, string) {
	return y, x
}
// Named return value(長い関数では見づらくなるので注意)
func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

if・for・switch

// ifの条件式を囲むカッコは不要.
// 変数宣言もできる.この変数はif・elseのスコープ内で有効.
if v := math.Pow(x, n); v < lim {
  return v
} else {
  fmt.Printf("%g >= %g\n", v, lim)
}

//forはCと同様,初期化ステートメント,条件式,後処理ステートメントを書く.
//Cと同じく,条件式だけあれば問題なく動作する.
for ; sum < 1000; {
	sum += sum
}
//条件式のみの場合はセミコロン省略可能.
for ; sum < 1000; {
	sum += sum
}
//条件すら省略すれば無限ループ
for  {
	sum += sum
}

//switch
// 条件は定数じゃなくても,intやstringでもOK
// フォールスルーしない(勝手にbreakしてくれる)
// 逆にフォールスルーしたい場合はfallthrough文を追加
switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
                 fallthrough
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
}
//switch(true)は省略可能
switch {
  case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
}

defer

//関数の実行をreturnまで遅延する(引数は即評価される)
func main() {
	defer fmt.Println("world")
	fmt.Println("hello")
        //hello
        //world
}
//deferの実行はスタック(LIFO)
func main() {
	fmt.Println("counting")
	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}
	fmt.Println("done")
}
/*
counting
done
9
8
7
6
5
4
3
2
1
0
*/