<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go:語法糖的代價(jià)

          共 4310字,需瀏覽 9分鐘

           ·

          2021-08-06 05:27

          點(diǎn)擊上方“Go編程時(shí)光”,選擇“加為星標(biāo)

          第一時(shí)間關(guān)注Go技術(shù)干貨!



          本文是 Go語言中文網(wǎng)組織的 GCTT 翻譯,發(fā)布在 Go語言中文網(wǎng)公眾號(hào),轉(zhuǎn)載請前往聯(lián)系授權(quán)。

          在 Go 語言中,你可以用少量的代碼表達(dá)很多東西。您通常可以查看一小段代碼并清楚地了解此程序的功能。這在 Go 社區(qū)中被稱為地道的 Go 代碼。保持跨項(xiàng)目代碼的一致性需要持續(xù)不斷地努力。

          當(dāng)我遇到 Go 的部分看起來不像地道 Go 代碼時(shí),這通常是有原因的。最近,我注意到 Go 中的接口切片(或抽象數(shù)組)工作方式有點(diǎn)怪異。這種怪異有助于理解在 Go 中使用復(fù)雜類型會(huì)帶來一些成本,而且這些語法糖[1]并不總是沒有代價(jià)的。為深入了解問題出現(xiàn)的原因,我對遇到的行為進(jìn)行拆分,這助于闡明 Go 的一些設(shè)計(jì)原則。

          # 舉例說明

          我們將編寫一個(gè)小型程序,它定義一個(gè)動(dòng)物列表(例如,dogs),并調(diào)用一個(gè)函數(shù),將每個(gè)動(dòng)物的噪聲輸出到控制臺(tái)

          animals := []Animal{Dog{}}
          PrintNoises(animals)

          程序成功通過編譯,并在控制臺(tái)打印出了“ Woof!”。下面就是這個(gè)程序的類似的版本:

          dogs := []Dog{Dog{}}
          PrintNoises(dogs)

          程序無法編譯,并將以下錯(cuò)誤打印到控制臺(tái),而不是輸出 "Woof!"

          cannot use dogs (type []Dog) as type []Animal in argument to PrintNoises

          如果你熟悉 Go,你可能會(huì)認(rèn)為應(yīng)該檢查一下 Dog 實(shí)現(xiàn)了 Animal,對吧? 如果是實(shí)現(xiàn)錯(cuò)誤,它的輸出應(yīng)該類似于

          cannot use dogs (type []Dog) as type []Animal in argument to PrintNoises: []Dog does not implement []Animal (missing Noise method)

          為什么第一個(gè)程序可以用 Dog 作為 Animal 來編譯和運(yùn)行,而第二個(gè)程序卻不能,即使它們看起來都是地道的和正確的

          下面是本例中用作參考的其余代碼。你可以通過編譯它,來了解上述用法的內(nèi)部原理

          type Animal interface {
            Noise() string
          }

          type Dog struct{}

          func (Dog) Noise() string {
            return "Woof!"
          }

          func PrintNoises(as []Animal) {
            for _, a := range as {
              fmt.Println(a.Noise())
            }
          }

          # 進(jìn)一步簡化問題

          讓我們試著用一種更簡單的方法來復(fù)現(xiàn)這個(gè)問題,以便更好地理解它。靜態(tài)類型檢查是一種有用的 Go pattern,用于斷言類型是否實(shí)現(xiàn)了接口。讓我們先檢查一下 Dog 是否實(shí)現(xiàn)了 Animal

          var _ Animal = Dog{}

          上面代碼編譯成功。那我們接下來就檢查程序中用到的 slices

          var _ []Animal = []Dog{}

          上面代碼沒有編譯成功,編譯器報(bào)錯(cuò):

          cannot use []Dog literal (type []Dog) as type []Animal in assignment

          現(xiàn)在,我們已經(jīng)復(fù)現(xiàn)了一個(gè)與例子類似(但不是完全相同)的錯(cuò)誤。利用這些不同的線索,我做了一些研究來找出如何解決這個(gè)問題,以及為什么會(huì)發(fā)生這樣的事情

          # 尋找解決方案

          在做了一些研究之后,我發(fā)現(xiàn)了兩件事:一個(gè)是解決方案,另一個(gè)是背后的原理。我們從修正程序開始,因?yàn)樗兄谡f明基本原理

          下面是最初未能編譯的代碼的一個(gè)修復(fù):

          dogs := []Dog{Dog{}}
          // 新邏輯: 把 dogs 的切片轉(zhuǎn)換成 animals 的切片
          animals := []Animal{}
          for _, d := range dogs {
            animals = append(animals, Animal(d))
          }
          PrintNoises(animals)

          通過將 Dog 的切片轉(zhuǎn)換為 Animal 的切片,現(xiàn)在可以將其傳入 Printnoise 函數(shù)并成功運(yùn)行。當(dāng)然,這看起來有點(diǎn)傻,因?yàn)樗旧鲜且呀?jīng)運(yùn)行的第一個(gè)程序的冗長版本。然而,在一個(gè)更大的項(xiàng)目中,這一點(diǎn)可能并那么明顯。修復(fù)的代價(jià)是多了四行代碼。這四行代碼似乎是多余,直到你開始考慮作為開發(fā)人員必須修復(fù)它的原因

          # 尋找原理

          現(xiàn)在你知道如何修復(fù)它,我們來探究它背后的原理。我找到了不錯(cuò)的解析:go 不支持切片中協(xié)變[2](譯者注: 協(xié)變[3]: 原文單詞為 covariance, 是指在計(jì)算機(jī)科學(xué)中,描述具有父/子型別關(guān)系的多個(gè)型別通過型別構(gòu)造器、構(gòu)造出的多個(gè)復(fù)雜型別之間是否有父/子型別關(guān)系的用語)

          換句話說,Go 不會(huì)執(zhí)行導(dǎo)致 O(N) 線性操作的類型轉(zhuǎn)換(如切片的情況),而是將責(zé)任委托給開發(fā)人員。也就是說,執(zhí)行這種類型的轉(zhuǎn)換是有成本的。不過,Go 并不是每次都這樣做。例如,當(dāng)將字符串轉(zhuǎn)換為 []byte 節(jié)時(shí),Go 將免費(fèi)為您執(zhí)行這種線性轉(zhuǎn)換,這可能是因?yàn)檫@種轉(zhuǎn)換通常很方便。這只是語言中語法糖的眾多例子之一。對于切片(和其他非基本類型),Go 選擇不為您承擔(dān)執(zhí)行此操作的額外成本

          這是有道理的——在我使用 Go 的 3 年里,這是我第一次遇到這種情況。這可能是因?yàn)?Go 在語法中灌輸了“simpler is better”的思想

          # 結(jié)論

          一門語言的作者通常會(huì)在語法糖方面做出權(quán)衡,有時(shí)他們會(huì)添加功能,即便這會(huì)使語言變得更加臃腫,有時(shí)他們會(huì)將成本轉(zhuǎn)嫁給開發(fā)人員。我認(rèn)為,不隱式地執(zhí)行高開銷的操作的決定在保持 Go 語言地道、整潔、可控上有積極的影響。

          上面的例子只是這個(gè)道理的一個(gè)應(yīng)用。這個(gè)例子表明,熟悉一種語言的習(xí)慣用法有副作用。對設(shè)計(jì)決策保持深思熟慮總是一個(gè)好主意,而不是期望語言或編譯器能幫到你。

          我鼓勵(lì)您在 Go 中尋找更多存在權(quán)衡語法的地方。它能幫助你更好地理解這門語言。我亦如此。

          # 引用

          以下是本文的引用:

          • GitHub Gist of the above example[4]

          • Go 語言官網(wǎng)[5]

          • Thread on covariance in Go[6]

          • Big-O notation[7]

          • Syntactic sugar[8]


          via: https://medium.com/@asilvr/the-cost-of-syntactic-sugar-in-go-5aa9dc307fe0

          作者:Katy Slemon[9]譯者:Alex1996a[10]校對:lxbwolf[11]

           參考資料

          [1]

          語法糖: https://en.wikipedia.org/wiki/Syntactic_sugar

          [2]

          go 不支持切片中協(xié)變: https://www.reddit.com/r/golang/comments/3gtg3i/passing_slice_of_values_as_slice_of_interfaces/

          [3]

          協(xié)變: https://zh.wikipedia.org/wiki/%E5%8D%8F%E5%8F%98%E4%B8%8E%E9%80%86%E5%8F%98

          [4]

          GitHub Gist of the above example: https://gist.github.com/asilvr/4d4da3cdc8180c5a9740d2890d833923

          [5]

          Go 語言官網(wǎng): https://golang.org

          [6]

          Thread on covariance in Go: https://www.reddit.com/r/golang/comments/3gtg3i/passing_slice_of_values_as_slice_of_interfaces/

          [7]

          Big-O notation: https://en.wikipedia.org/wiki/Big_O_notation

          [8]

          Syntactic sugar: https://en.wikipedia.org/wiki/Syntactic_sugar

          [9]

          Katy Slemon: https://medium.com/@katyslemon

          [10]

          Alex1996a: https://github.com/Alex1996a

          [11]

          lxbwolf: https://github.com/lxbwolf

          [12]

          GCTT: https://github.com/studygolang/GCTT

          [13]

          Go 中文網(wǎng): https://studygolang.com/


             


          喜歡明哥文章的同學(xué)
          歡迎長按下圖訂閱!

          ???

          瀏覽 55
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性开放网站 | 国产内射网站 | 成人激情四射视频婷婷丁香网 | 成人久久久久久无码 | 欧洲在线视频 |