Open3

Golang

こなゆうこなゆう

A Tour of Go メモ

https://go-tour-jp.appspot.com/list

YouTubeのvideoIDが不正ですhttps://youtube.com/playlist?list=PL6fOO2RfONsU7E_Z80mPs-UYc437tLTkl

Exercise: Errors

注意: Error メソッドの中で、 fmt.Sprint(e) を呼び出すことは、無限ループのプログラムになることでしょう。

https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/fmt/print.go;l=62

switch v := p.arg.(type) {
    case error:
	handled = true
	defer p.catchPanic(p.arg, verb, "Error")
	p.fmtString(v.Error(), verb)
	return

errorはv.Error()でエラーを呼んでいるのでループする

package main

import (
	"fmt"
	"math"
)

const dz = 1e-10

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %d", float64(e))	
}

func Sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, ErrNegativeSqrt(x)
	}
	
	z, d := x, 0.0
	
	for math.Abs(z - d) > dz {
		d, z = z, z-(z*z - x) / (2 * z)
	}
	
	return z, nil
}

func main() {
	fmt.Println(Sqrt(2))
	fmt.Println(Sqrt(-2))
}
こなゆうこなゆう

埋め込まれたインターフェースの実装を動的に変更する

https://tenntenn.dev/ja/posts/qiita-eac962a49c56b2b15ee8/

func main() {
	p := NewPerson("ko", "na", 23)
	fmt.Println(p) // ko na (23)

	p.SetStringer(func(p *Person) string {
		return fmt.Sprintf("名前は%s%s。年齢は%dです。", p.FirstName, p.LastName, p.Age)
	})
	fmt.Println(p) // 名前はkona。年齢は23です。
}

type stringer fmt.Stringer

type Person struct {
	stringer
	FirstName string
	LastName  string
	Age       int
}

type StringerFunc func() string

func (sf StringerFunc) String() string { // StringerFunc型にString()メソッドを実装するための記述(fmt.Stringerを満たすようにする)
	return sf()
}

func NewPerson(firstName, lastName string, age int) *Person {
	p := &Person{
		nil,
		firstName,
		lastName,
		age,
	}

	p.stringer = StringerFunc(func() string {
		return fmt.Sprintf("%s %s (%d)", p.FirstName, p.LastName, p.Age)
	})

	return p
}

func (p *Person) SetStringer(sf func(p *Person) string) {
	p.stringer = StringerFunc(func() string {
		return sf(p)
	})
}
こなゆうこなゆう

Goroutines

main関数、GCもgoroutine。

goroutineは、同じアドレス空間で実行される。以下の例では、goroutineを実行する準備をしている間にfor文は5回回りきってしまうため、fmt.Println("world", i)がiを表示するときには、iは5になっている。

func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	for i := 0; i < 5; i++ {
		go func() {
			time.Sleep(100 * time.Millisecond)
			fmt.Println("world", i)
		}()
	}

	say("hello")
}
world 5
hello
world 5
world 5
world 5
world 5
hello
hello
hello
hello

Channels

自分的には、「データ構造がキューである筒」みたいなイメージ。

c <- numberを行うたびに、cという筒にqueueしている。
receiveNumber := <-cと行うたびに、cという筒からdequeueしている。