Closed20

tour of goで学んだことのメモ

nozominozomi

Named return values

Goでの戻り値となる変数に名前をつける( named return value )ことができます。戻り値に名前をつけると、関数の最初で定義した変数名として扱われます。
https://go-tour-jp.appspot.com/basics/7

package main

import "fmt"

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
        // return x yとしなくてもx, yをリターンしてくれる(naked return)
	return
}

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

if

Goのifは()は不要で{}は必須

if x < 0 {
	return sqrt(-x) + "i"
}
nozominozomi

If with a short statement

ifの条件部分で宣言された変数はifのスコープ内でのみ有効

nozominozomi

Defer

defer ステートメントは、 defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させるものです。
defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。
https://go-tour-jp.appspot.com/flowcontrol/12

nozominozomi

Stacking defers

defer へ渡した関数が複数ある場合、その呼び出しはスタック( stack )されます。 呼び出し元の関数がreturnするとき、 defer へ渡した関数は LIFO(last-in-first-out) の順番で実行されます。
https://go-tour-jp.appspot.com/flowcontrol/13

最後から最初って順番で実行される

nozominozomi

Pointers to structs

structのフィールドは、structのポインタを通してアクセスすることもできます。
https://go-tour-jp.appspot.com/moretypes/4

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v
	p.X = 300
	fmt.Println(v)
}

vの値は{300, 2}になる

nozominozomi

Arrays

var a [10]int

10個の数字の配列を宣言している

nozominozomi

Slices

配列は固定長です。一方で、スライスは可変長です。より柔軟な配列と見なすこともできます。 実際には、スライスは配列よりもより一般的です。
https://go-tour-jp.appspot.com/moretypes/7

sliceとmapの違いを完全理解した

nozominozomi

Slices are like references to arrays

スライスは配列への参照のようなものです。
スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。
https://go-tour-jp.appspot.com/moretypes/8

sliceは参照しているだけなので、sliceの値を変更したら元の配列の値も変わるよって理解

nozominozomi

Function closures

package main

import "fmt"

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

sumの値はpos, negで別れているが、それぞれで参照されている(sumの値は引き継がれる)

nozominozomi

Methods

型にメソッド( method )を定義できます。

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Vertexという型にAbsという関数を定義している

nozominozomi

Pointer receivers

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}

func (v *Vertex) Scale(f float64) {*があることでVertext{3, 4}の値を変更することができる

nozominozomi

https://go-tour-jp.appspot.com/methods/6

メソッドがポインタレシーバである場合、呼び出し時に、変数、または、ポインタのいずれかのレシーバとして取ることができます:
https://go-tour-jp.appspot.com/methods/6

var v Vertex
v.Scale(5)  // OK
p := &v
p.Scale(10) // OK

vはポインタではないがGoのほうでポインタレシーバとして自動的に呼び出されるためコンパイルが通る

nozominozomi

Choosing a value or pointer receiver

値レシーバとは?

func (p Person) Greet(msg string) {
    fmt.Printf("%s, I'm %s.\n", msg, p.Name)
}

ポインタレシーバとは?

func (pp *Person) Shout(msg string) {
    fmt.Printf("%s!!!\n", msg)
}
nozominozomi

Interface values

package main

import (
	"fmt"
	"math"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

type F float64

func (f F) M() {
	fmt.Println(f)
}

func main() {
	var i I

	i = &T{"Hello"}
	describe(i)
	i.M()

	i = F(math.Pi)
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}

describe(i)でvalueと、型を引数として渡していることが分かる

nozominozomi

The empty interface

interface{}はjsでいうanyに近い

このスクラップは2022/07/31にクローズされました