ys memos

Blog

go勉強メモ


go

2021/08/18


そろそろ Golang へ入門したいと思い,LeetCode を通して Golang を触りの部分ですが,はじめてみました.

これまでは LeetCode は C++で解いていたため,C++との差に対して過度に反応しています.

同じく C++を触っていて,Golang を始める方にとっては読み物としてお役に立つかもしれません.よかったら作業の脇に置いてみてください.



if-else で対応


変数を使っていないと怒ってくれる.使わない戻り値は_対応.


struct とメソッドで対応.(個人的に,クラスをなくしたのは英断だと思う)

自分で簡単なライブラリを作る時は,横着して class 内に実装を書いてしまうので,それを強制的に回避させられているので,今までの横着さを反省した.


struct にメソッドを追加する際,大文字スタートであればパブリック,小文字スタートであればプライベートのように,命名規則で扱いが変わる.


C++とは違い,インデックスとイテレータを同時に取ることができる

range-loop
for i, v := range nums {
	//TODO: 要らない方は_で対応
}

map で対応


list で対応


C++の bitset よくわかってなかったので,助かった.

uint で対応


C++で複数の戻り値を受ける場合,関数の戻り値を std::tuple<T1,T2>()としつつ,std::tie()をする必要があるが,Go では自動で受け取ってくれる.必要ない値を受け取らなくてはならない時,_で対応.

error 型が帰ってくるのが,競プロなどでは不要だが,真面目な開発などでは便利そう(やったこと無いが).


ラムダ式とか関係なく関数の中に関数を書くことができる

inner_func
func hoge() {
	fuga := func () {
		fmt.Println("fuga")
	}
    fmt.Println("hoge")
    fuga()

    var recurser func (T1, T2) T
    recurser = func (v1 T1, v2 T2) {
    	return recurser(v1, v2)
    }
}

例えば,降順にするカスタムソートを作る場合,byLess などといった名称で構造体を作り,そこに Len()Swap(i, j int)Less(i, j int)のような関数を作り,sort.Sort(byLess(nums))のように呼び出す.

C++であれば,sort(nums.begin(), nums.end(), [](int a, int b) {})のように比較方法を指定することができ,数行で簡潔に書くことができるのに対し,冗長に感じた.

しかし,簡単な構造体に対するソートが冗長であるのに対して,複雑な構造体に対して複数のソートパターンを準備しておきたい開発では,こちらのほうが優位であるように感じる.byLessbyFrequency など,ひと目でわかりやすいソートを開発できそう.

抽象化という観点ではこちらのほうが良く,呼び出す行では簡潔になる印象.


悲しい.

が,複数人開発では助かりそう.(ネストされた三項演算子は苦手)


queue が無いのはかなりよいことだと思う一方で,listinterface{}型になっており,BFS の探索箇所を list で管理しようとする.(Node)など付ける必要があるようで,かなり複雑になって悲しい.

実際,Golang に慣れるために LeetCode を使わせてもらったが,木の探索系は C++に逃げたりもした.


C++では暗黙的に true/false にしてくれていたところを Go では明示的にする必要がある.

動作をある程度把握していると文字数的にも見た目的にも簡潔になるため,好んで使っているのだが,それによって謎のバグが生じる可能性を考えると,一概に嫌なことではないのかもしれない.

だがやはり,nullptrint 型の 0 を false にしてくれないこと.


C++であれば,関数の引数に&を付けると参照渡しになってくれるのに対し,Go では呼び出しの際に引数に&を付けるので,知らない間に変数の値が変わっていることがない(かも).


記述が簡潔になる一方で,変数かポインタかを意識せずにメソッド等にアクセスできちゃう.


代わりに byte 型と rune 型を使う.



nums := []T{ n1, n2, n3}
strs := []string {""}
var strs []string

size_of_array
len(nums)

append()で第二引数をスプレッドしちゃう.

letters = append(letters, subletters...)

uint8 のエイリアスらしい.int 型と同様,計算可能.

ascii-calc
str[i] - '0'

create_map
mp := make(map[KeyT]ValT)

struct からオブジェクト(?)を作る時に,右辺に&を付けるとポインタになってくれる.

ちなみに,ポインタを受け取る関数にポインタを渡す時も同様,&を付けるとよい.


木や双方向リストを実装する時には大抵,TreeNode*とか Node*とか作ると思うけど,そんな時は以下のようにするとよい.

nested_struct
type Node struct {
	Val int
	Prev *Node
	Next *Node
}

// こんなふうにすると使いやすい
func NewNode(val int, prev, next, *Node) *Node {
	retunr &Node{val, prev, next}
}

node := NewNode(2, node1, node2)
node := NewNode(1, nil, nil)

map
// 初期化
const keyval := map[keyType]valType {	key1: val1,	key2: val2,	key3: val3,}
delete(keyval, key1) // 削除
if _, ok := m[key2]; ok {
	// found
} else {
	// not found
}


sort
# sort.Types(arr)の書式
sort.Ints(nums)


newletters := make([]string, len(letters))
copy(newletters, letters)

swap
node.Val, node.Next.Val = node.Next.Val, node.Val

check_null
if node == nil {
	return nil
}

alt_hashset
st := make(map[int]bool)// insert
st[0] = true// erase
st[0] = false// contains
if st[0] == true {
	// found
} else {
	// not found
}

alt_queue
l := list.New()
for _, num := range nums {
	l.PushBack(num)
}
for la.Len()>0 && lb.Len()>0 {
	lfront := l.Front()
	num := lfront.Value.(int32) // interface{}型であることに注意
	fmt.Println(num)
	l.Remove(lfront)
}

cast
num := int(fnum) // float->intは切り捨て
fnum = float64(num)
str := string(1 + '0') // "1"になる

cut
fnum = math.Floor(fnum)

alt_vector
nums := make([]int, num_size, capacity)

return_slice
return []int{0, 1, 2}


abs
func abs_of(num int)int {
	if num>0 {
		return num
	} else {
		return -num
	}
}

sum_of()
func sum_of(nums []int) int {
	sum_num := 0
	for _, num := range nums {
		sum_num += num
	}
	return sum_num
}

func sum_of(num1, num2 int) int {
	return num1 + num2
}

C++でも普通に使うような,ビットシフト演算

bitmask
func bitmask(digit uint) uint {
	return 1 << digit
}

checkbit
func checkbit(num uint, digit uint) bool {
	if num & bitmask(digit) != 0 {
		return true
	} else {
		return false
	}
}

C++の std ライブラリに含まれていて,重複しているもの(stack,queue,list)が軒並み削られており,各人が利用する標準ライブラリが相違することは少なそうな印象.しかし,「C++のこれがない」となった時に,その中身を全く知らない場合は,代替となるものを見極めるのが難しそうな印象. その一方で,http などの,boost などのサードパーティライブラリに含まれているような処理が standard library になっているという面もあった.

また,C++の std を使えば簡潔に書けるものが,結構長いコードになる面も感じていて,競技プログラミングには向かないのかもしれない.

しかし,エラーの扱い方が結構決まっており,アプリ開発などの用途においては非常に使いやすそう.さらに,

なので,LeetCode の木探索や AtCoder をやる時は C++を使い,アプリ開発などでは Golang を使う王と思った.


関連タグを探す