IkumaTadokoro / diary

MIT License
0 stars 0 forks source link

2022-08-20 #68

Open IkumaTadokoro opened 2 years ago

IkumaTadokoro commented 2 years ago

Goやっていくぞ。読めるようになるにもどういう知識が必要かわからないので、

https://docs.google.com/presentation/d/1RVx8oeIMAWxbB7ZP2IcgZXnbZokjCmTUca-AbIpORGk/edit#slide=id.g4f417182ce_0_80

これをやっていく

IkumaTadokoro commented 2 years ago

https://docs.google.com/presentation/d/1Z5b5fIA5vqVII7YoIc4IesKuPWNtcU00cWgW08gfdjg/edit#slide=id.g4f6f42e26c_0_1

次は基本構文編

https://docs.google.com/presentation/d/1CIMDenDLZ7NPNgzmfbCNH_W3dYjaTEBdUYfUuXXuMHk/edit#slide=id.g4e29971f9a_0_0

Goは静的型付け言語 変数宣言

var n int = 100
var n = 100 // 型推論
n := 100 // 関数ないのみで利用可能
var (
    n = 100
    m = 200
)

int型がint, int8, int16とビット単位である。

型ごとのデフォルト値「ゼロ値」が決まっている。 お〜GoLand側で型推論できる場合は消すようにサジェスチョンが出るのか。

定数宣言

const n int = 100

お〜文字列はシングルクォーとしか使えないんだな。

iota、とりあえずいい感じの連番と理解

FizzBuzzやったので、次は関数

https://docs.google.com/presentation/d/1DtWB-8FcnNb9asxSpIaOLYbAEc9OjBAwMLNxKnPA8pc/edit#slide=id.g4cbe4d134e_0_0

なるほど、複数のデータ型があつまると、コンポジット型だと。スライス型ってのは面白いな。名前の意味はわかるけど今までの言語では見ていないかも。

お〜配列の要素数が変更できない!いいね〜

IkumaTadokoro commented 2 years ago

とりあえず「全く知らない」から、FizzBuzzできるくらいまでには進化。

https://zenn.dev/nobonobo/articles/e0af4e8afc6c38b42ae1

とりあえずわかるのは「Goに入ってはGoに従え」は本当にそうした方がいい。Ruby→JavaScriptに比べてだいぶ経路が違う。 書けるようになっても、ちゃんとやらないとGo本来の実力を引き出せない。なんでそう書くのかを言語仕様と照らし合わせないとダメ

IkumaTadokoro commented 2 years ago

Goのツールチェーンに対して感じる便利さはDenoに近いものがある

IkumaTadokoro commented 2 years ago

https://zenn.dev/kotap15/articles/b6f6d8ce421d67

A Tour of Goをやろう。

https://go-tour-jp.appspot.com/welcome/1

IkumaTadokoro commented 2 years ago
import "fmt"
import "math"

// factored import statement: こっちが一般的
import (
    "fmt"
    "math"
)

大文字だと自動的に外部パッケージに公開される。逆に小文字だと公開されない。

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

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

Goの型宣言。C以外の言語では名前: 型宣言となることが多いが、Goでは簡潔さをめざしコロンを削除したとのこと。

// 型が同じ場合は宣言を最後だけにすることができる。
func add(x, y int) int {
    return x + y
}
// 複数の戻り値を返すこともできる
func swap(x, y string) (string, string) {
    return y, x
}
// 戻り値に名前をつける: named return value
// 名前をつけた戻り値の変数を使うと、return ステートメントには何も書かずに戻すことができる
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}
// Variables
var isExpensive bool
var i, j int = 1, 2
package main

import "fmt"

func main() {
    k := 3
    fmt.Println(k)
}
var i int = 24
// 型変換(Type Conversions)
var f float64 = float64(i)
package main

func main() {
    var i int
    j := i // jはintとして推論される(Type Interface)
}
// 定数宣言
// 定数は`:=`で宣言できない。
const Pi = 3.14

// 型のない数値の定数は値に応じて必要な型をとる
const Big = 1 << 100

ここまででPacakages, varibales, and functionsが終了

IkumaTadokoro commented 2 years ago

Forループ

package main

import "fmt"

func main() {
    sum := 0
    // 条件部分のカッコは省略できる。中括弧を省略することはできない。
    for i = 0; i < 10; i++ {
        sum += i
    }
    fmt.Println(sum)
}
package main

import "fmt"

func main() {
    sum := 1
    // 初期化処理と後処理ステートメントの記述は任意
    fot sum < 1000 {
        sum += sum
    }
    fmt.Println(sum)
}
package main

import "fmt"

func main() {
    // 無限ループ
    for {
        fmt.Println("hoge")
    }
}
import "fmt"

// if文も条件部分のカッコを省略することができる
if x < 0 {
    fmt.Println("minus")
}
import "math"

// ifステートメントの中では簡単なステートメントを書くことができる
if v := math.Pow(x, n); v < lim {
    return v
}
package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on")
    // breakは不要
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
    fmt.Printf("%s.\n", os)
    }
}
pakage main

import "fmt"

func main() {
    // defer: deferへ渡した関数の実行s、呼び出し元の関数の終わりまで遅延させるもの
    defer fmt.Println("world")
    fmt.Println("hello")
}

// この場合、main()が呼び出し元になるので、その関数の終わり(つまり"hello"が表示されるまで)呼び出されることはない

deferが複数ある場合には、deferされた関数はスタックされ、LIFOで呼び出される。

ここまででFlow Control statements: form if, else, switch and deferが完了

IkumaTadokoro commented 2 years ago

ここからPointerか。今日中には終わらせるけど、じっくりやっていくぞ。

Goはポインタを扱います。ポインタは値のメモリアドレスを指します。

なんとなくわかるけど、なんのために使うのかわかっていない。

変数Tのポインタは、*T型で、ゼロ値はnilである。あれ、そういやnullじゃなくてnilなんだな。

var p *int

&オペレータでそのオペランドへのポインタを引き出す。

i := 42
p = &i

*オペレータは、ポインタの指す先の変数を示す。

i := 42
p = &i
fmt.Println(*p)

これを"dereferencing"または"indirecting"と呼ぶそうな。確かにそんな感じはする。

// 構造体
type Hoge struct {
    X int
    Y int
}

func main() {
    hoge := Hoge{1, 2}
    fmt.Println(hoge.X)
    hoge.X = 4
    fmt.Println(hoge.X)
}
type Vertex struct {
    X, Y int 
} 

var (
    v1 = Vertex{X: 1} // これがName構文で、フィールドの一部だけを指定することができる
)

[n]T型は、型Tのn個の変数の配列を表す。

var array [2]string // 要素数2この配列

配列の要素数を変えることはできない。配列は固定長だが、スライスは可変長。型[]Tは型Tのスライス

var slice []int // int型のスライス
primes := [4]int{2, 3, 5, 7}
s = primes[0:2]

スライスはスライスという独自なものではなくて、配列の部分列。スライスの要素を変更すると、元となる配列が変更される。 スライスはコロンで区切られたインデックスによって元の配列の部分を指定する。半開区間なので、上限の方は含まない。

スライスする時の下限と上限をそれぞれ省略した場合には、デフォルトの値が採用される。下限は配列の最初で、上限は配列の最後。

スライスには長さと容量の2つの属性がある。長さはスライス自体の長さで、容量はスライスの最初の要素から数えて元となる配列の要素数

スライスのゼロ値はnil。

組み込みのmake関数を使ってスライスを作成する。

package main

import "fmt"

func main() {
    // ゼロ化された配列を割り当て、その配列を指すスライスを返す
    a := make([]int, 5)

    // ゼロ化された配列を割り当て、その配列かつ指定した容量のスライスを返す
    b := make([]int, 0, 5)
}

rangeはforループに利用し、スライスやマップを一つずつ反復処理するために使用する。

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    // indexとvalueを返している
    for i, v := range pow {
        fmt.Printf("3**%d = %d\n", i, v)
    }
}

必要ない値は_で捨てることができる。

とりあえずBasicまでは終わった...。

IkumaTadokoro commented 2 years ago

とりあえずソースコードを落としてみた。

https://github.com/chromedp/pdlgen

全くわからないという感じではないけれど、読むのに時間かかりそう。このコードを読みながらGoの文法を定着させていきたい。