處理上面經常是拿到 GPS 座標,或是直接拿到地址。 地址是可以方便人類來閱讀的,但是真正要電腦能夠處理的就是經緯度的座標位置。 如果要對某一個座標找尋出距離三公里距離的所有座標,那是不是需要把資料庫裡面的地點全部拿來計算呢? 這裡介紹了一種方式叫做 K-D Tree 。
K-D Tree 的方法就是將地圖平面透過二分法的方式來切割,將每兩個點找出距離後作為一個區塊。透過這樣的方式可以很快速地找出兩個最相近的距離點。
如何將搜尋結果作 Caching
如果有一群人同時開 LINE SPOT 需要尋找三公里內所有座標,那麼有方式可以快速的暫存起來資料,並且快速的回覆使用者的需求嗎? 這時候可以考量使用 Hashing 的方式來將經緯度數值直接轉換成一串文字,透過這個方式可以快速找到上一次搜尋的結果。如果沒有搜尋過才去跑 K-D Tree 的搜尋,這樣一來就可以在不經過複雜的運算就可以快速的回覆使用者。
也就是說,在強型態程式語言中,因為型態都必須去先給與。撰寫 function 的時候很難將型態加以抽象畫。 讓型態可以事後在套入。拿個簡單的例子來說,根據文章 “Why Gnerics” 曾經舉過這個很棒的範例。先假設你需要將一個 slice 裡面所有元素從小到大來排序。
根據 Int 你可能會寫:
func ReverseInts(s []int) []int {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
return s
}
而如果是字串的時候,可能如下:
func ReverseInts(s []string) []sting {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
return s
}
根據以上的方式,你會發現兩個 function 其實真的沒有任何的差異。但是卻由於資料格式不同,需要特地用兩個 function 分開來撰寫。 這樣對於維護上往往不直覺,以後發現其中可以優化或是有問題的時候,就一次需要把所有用到型態的程式碼都一起維護,相當的不直覺。
What happened to contracts?
An earlier draft design of generics implemented constraints using a new language construct called contracts. Type lists appeared only in contracts, rather than on interface types. However, many people had a hard time understanding the difference between contracts and interface types. It also turned out that contracts could be represented as a set of corresponding interfaces; there was no loss in expressive power without contracts. We decided to simplify the approach to use only interface types.
func ReverseSlice[T any](s []T) []T {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
return s
}
func main() {
fmt.Println(ReverseSlice([]string{"Hello", "playground"}))
fmt.Println(ReverseSlice([]int{1, 3, 5}))
}
Type Parameters加上限制
使用 any Type Parameter 其實相當的方便,但是往往取決於你可能處理的資料並不適合所有的型態的時候。其實需要加上一些資料的限制。 舉個例子來說明:
範例: 兩個參數取比較大的
if a < b {
return a
}
return b
這是一個相當簡單的比較方式,但是可以看到如果將這個方式透過 Type Parameters 來撰寫。會發現輸入的參數將不支援 string ,所以需要以下的相關修改。
https://go2goplay.golang.org/p/9BgTT0hCgD7
type numeric interface {
type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64
}
func min[T numeric](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(min(42, 84))
fmt.Println(min(3.14159, 2.7182))
}
小結論:
Type Parameters 與 Go2 Playground 其實還在開發中,使用上也沒有那麼直觀與好用之外,可能還有一些 bugs 。 不過真的很期待使用 Type Parameters 讓開發上可以真正將演算法與型態脫鉤,讓 function 能夠更簡潔。