Golang:三個(gè)常見的編程問(wèn)題
每種語(yǔ)言都是唯一的。 這些常見的編程挑戰(zhàn)的解決方案在Java(我以前最喜歡的編程語(yǔ)言)中非常不同。 而且,如果我敢說(shuō)這一點(diǎn),那么用Java更直觀地解決這些問(wèn)題。
Golang有解決這些問(wèn)題的獨(dú)特方法。 我下面列出的解決方案最初對(duì)我來(lái)說(shuō)不是很直觀,但是現(xiàn)在已經(jīng)成為第二自然。 我不確定它們是否是"慣用的GO"-坦率地說(shuō),我不知道什么是慣用的GO。
也許會(huì)有更好的,不同的方式來(lái)解決這些問(wèn)題-我很想聽聽您的想法。
因此,讓我們深入研究編程挑戰(zhàn)。
問(wèn)題1:我需要維護(hù)一組"物品"。 但是,哦,不,Golang沒(méi)有" Set"數(shù)據(jù)結(jié)構(gòu)。
解決方案之一:Golang沒(méi)有"Set",但有"Map"。 映射的鍵集是一組唯一的項(xiàng)目。
您可以執(zhí)行以下操作(https://play.golang.com/p/tayo3H5mi56):
- package main
- import "fmt"
- type Set struct {
- m map[string]bool
- }
- func NewSet() Set {
- m := make(map[string]bool)
- return Set{m: m}
- }
- func (s *Set) Contains(val string) bool {
- _, ok := s.m[val]
- return ok
- }
- func (s *Set) Add(val string) {
- s.m[val] = true
- }
- func (s *Set) Remove(val string) {
- delete(s.m, val)
- }
- func main() {
- s := NewSet()
- s.Add("foo")
- fmt.Printf("s has foo: %t. s has bar: %t\n", s.Contains("foo"), s.Contains("bar"))
- s.Remove("foo")
- fmt.Printf("s has foo: %t. s has bar: %t\n", s.Contains("foo"), s.Contains("bar"))
- }
將映射用作集合的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)的優(yōu)點(diǎn)是,您仍然受益于超快速的映射鍵查找,基礎(chǔ)哈希優(yōu)化,并且最終編寫的代碼更少。
問(wèn)題2:我需要比較兩個(gè)值,但" =="并不總是有效。
解決方案之一:讓我們了解" =="在哪里起作用,在哪里不起作用。
包含地圖或切片的結(jié)構(gòu)
- type ABC struct {
- a int
- b string
- c []int
- }
- Error:
- invalid operation: a == b (struct containing []int cannot be compared)
帶指針的結(jié)構(gòu)。
好吧,實(shí)際上指針是可以比較的,但是它們并不總是能為您提供理想的結(jié)果。
- a, b := 1, 1
- fmt.Println(&a == &b) // False
輸入reflect.DeepEqual
現(xiàn)在,這將可以按需工作(大多數(shù)情況下):
- //ABC - A simple type
- type ABC struct {
- a int
- b string
- c []int
- }
- var a = ABC{a: 1, b: "10", c: []int{1, 2}}
- var b = ABC{a: 1, b: "10", c: []int{1, 2}}
- reflect.DeepEqual(a, b)
- Example #2
- a, b := 1, 1
- fmt.Println(&a == &b) // False
- fmt.Println(reflect.DeepEqual(&a, &b)) // True
它將為您帶來(lái)更好的結(jié)果-但是,如果您的結(jié)構(gòu)中有浮點(diǎn)數(shù)或時(shí)間字段,則需要忽略。 您將需要編寫自定義的equals方法
- //ABC - A simple type
- type ABC struct {
- a int
- b string
- t time.Time // Ignore time while comparing to structs
- }
- var a = ABC{a: 1, b: "10", t: time.Now()}
- var b = ABC{a: 1, b: "10", t: time.Now()}
- fmt.Println(a == b, equals(a, b))
- func equals(val1, val2 ABC) bool {
- return val1.a == val2.a && val1.b == val2.b
- }
除非您別無(wú)選擇,否則您將不希望編寫自定義的equals函數(shù)-但是,與==運(yùn)算符相比,您應(yīng)該更喜歡reflect.DeepEqual嗎? 本質(zhì)上,如果==將為true,則保證reflect.DeepEqual為true,反之則不為true。 因此,默認(rèn)情況下可以使用reflect.DeepEqual。 除非您有性能限制,否則:
- func BenchmarkOperator(t *testing.B) {
- for i := 0; i < t.N; i++ {
- if a == b {
- }
- }
- }
- func BenchmarkReflectDeep(t *testing.B) {
- for i := 0; i < t.N; i++ {
- if reflect.DeepEqual(a, b) {
- }
- }
- }
- BenchmarkOperator-8 44614131 24.8 ns/op 0 B/op 0 allocs/op
- BenchmarkReflectDeep-8 823174 1558 ns/op 96 B/op 2 allocs/op
" =="比reflect.DeepEqual快。 更快。
問(wèn)題#3:我需要使用結(jié)構(gòu)作為映射的鍵-但我的結(jié)構(gòu)包含要忽略的切片,指針或字段。
解決方案之一:Golang中的映射鍵評(píng)估使用==運(yùn)算符,而不使用reflect.DeepEqual。
解決此問(wèn)題的一種方法是使用自定義密鑰創(chuàng)建邏輯。
- //Obvious solution that will not work
- type A struct {
- i *int
- }
- i, j := 1, 1
- a, b := A{i: &i}, A{i: &j}
- m := map[A]bool{}
- m[a] = true
- _, ok := m[b]
- fmt.Println(ok) // False key b doesn't exist in map m
- //Custom keys- solution
- func customKey(a A) int {
- return *a.i
- }
- i, j := 1, 1
- a, b := A{i: &i}, A{i: &j}
- m := map[int]bool{}
- m[customKey(a)] = true
- _, ok := m[customKey(b)]
- fmt.Println(ok)// This will return true
獎(jiǎng)勵(lì)問(wèn)題:如何比較兩個(gè)地圖? [問(wèn)題2和問(wèn)題3的推論]
https://play.golang.com/p/0ac2HIyiJ9g
- key, val := "key", "val"
- key1, val1 := "key", "val"
- abc := map[*string]string{&key: val}
- abc2 := map[*string]string{&key1: val1}
- def := map[string]*string{key: &val}
- def2 := map[string]*string{key1: &val1}
- fmt.Println(reflect.DeepEqual(abc, abc2)) //false
- fmt.Println(reflect.DeepEqual(def, def2)) //true
首先要注意的是,您不能通過(guò)==運(yùn)算符比較地圖。 您可以通過(guò)reflect.DeepEqual比較兩個(gè)地圖。 按照reflect.DeepEqual規(guī)則,將映射鍵與==運(yùn)算符進(jìn)行比較,并將值與reflect.DeepEqual進(jìn)行遞歸比較。