1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      go語言type go語言type理解

      go語言中的type后面跟著的是名字還是類型

      正式場合多稱呼姓氏,熟人之間多叫名字。另外在英語中,名字很少,而姓氏眾多,所以,叫姓氏比較不容易重名。

      專注于為中小企業(yè)提供網(wǎng)站設(shè)計、成都網(wǎng)站制作服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)容城免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。

      如何看待go語言泛型的最新設(shè)計?

      Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現(xiàn)實。Go 團隊實施了一個看起來比較穩(wěn)定的設(shè)計草案,并且正以源到源翻譯器原型的形式獲得關(guān)注。本文講述的是泛型的最新設(shè)計,以及如何自己嘗試泛型。

      例子

      FIFO Stack

      假設(shè)你要創(chuàng)建一個先進先出堆棧。沒有泛型,你可能會這樣實現(xiàn):

      type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{

      return?s[len(s)-1]

      }

      func?(s?*Stack)?Pop()?{

      *s?=?(*s)[:

      len(*s)-1]

      }

      func?(s?*Stack)?Push(value?interface{})?{

      *s?=?

      append(*s,?value)

      }

      但是,這里存在一個問題:每當(dāng)你 Peek 項時,都必須使用類型斷言將其從 interface{} 轉(zhuǎn)換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯誤。比如忘記 * 怎么辦?或者如果您輸入錯誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會發(fā)現(xiàn)到自己的錯誤,直到它影響到你的整個服務(wù)為止。

      通常,使用 interface{} 是相對危險的。使用更多受限制的類型總是更安全,因為可以在編譯時而不是運行時發(fā)現(xiàn)問題。

      泛型通過允許類型具有類型參數(shù)來解決此問題:

      type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{

      return?s[len(s)-1]

      }

      func?(s?*Stack(T))?Pop()?{

      *s?=?(*s)[:

      len(*s)-1]

      }

      func?(s?*Stack(T))?Push(value?T)?{

      *s?=?

      append(*s,?value)

      }

      這會向 Stack 添加一個類型參數(shù),從而完全不需要 interface{}。現(xiàn)在,當(dāng)你使用 Peek() 時,返回的值已經(jīng)是原始類型,并且沒有機會返回錯誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)

      此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進制大小為代價)。如果我們對上面的非泛型代碼和泛型代碼進行基準(zhǔn)測試,我們可以看到區(qū)別:

      type?MyObject?struct?{

      X?

      int

      }

      var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{

      for?i?:=?0;?i??b.N;?i++?{

      var?s?Stack

      s.Push(MyObject{})

      s.Push(MyObject{})

      s.Pop()

      sink?=?s.Peek().(MyObject)

      }

      }

      func?BenchmarkGo2(b?*testing.B)?{

      for?i?:=?0;?i??b.N;?i++?{

      var?s?Stack(MyObject)

      s.Push(MyObject{})

      s.Push(MyObject{})

      s.Pop()

      sink?=?s.Peek()

      }

      }

      結(jié)果:

      BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op

      在這種情況下,我們分配更少的內(nèi)存,同時泛型的速度是非泛型的兩倍。

      合約(Contracts)

      上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實現(xiàn) String() 函數(shù)

      沒有類,C語言有結(jié)構(gòu)體,那么Go的結(jié)構(gòu)體有什么特別之處?

      Go語言中沒有“類”的概念,也不支持“類”的繼承等面向?qū)ο蟮母拍睢o語言中通過結(jié)構(gòu)體的內(nèi)嵌再配合接口比面向?qū)ο缶哂懈叩臄U展性和靈活性。

      自定義類型

      在Go語言中有一些基本的數(shù)據(jù)類型,如string、整型、浮點型、布爾等數(shù)據(jù)類型, Go語言中可以使用type關(guān)鍵字來定義自定義類型。

      自定義類型是定義了一個全新的類型。我們可以基于內(nèi)置的基本類型定義,也可以通過struct定義。例如:

      通過Type關(guān)鍵字的定義,MyInt就是一種新的類型,它具有int的特性。

      類型別名

      類型別名是Go1.9版本添加的新功能。

      類型別名規(guī)定:TypeAlias只是Type的別名,本質(zhì)上TypeAlias與Type是同一個類型。就像一個孩子小時候有小名、乳名,上學(xué)后用學(xué)名,英語老師又會給他起英文名,但這些名字都指的是他本人。

      type TypeAlias = Type

      我們之前見過的rune和byte就是類型別名,他們的定義如下:

      類型定義和類型別名的區(qū)別

      類型別名與類型定義表面上看只有一個等號的差異,我們通過下面的這段代碼來理解它們之間的區(qū)別。

      結(jié)果顯示a的類型是main.NewInt,表示main包下定義的NewInt類型。b的類型是int。MyInt類型只會在代碼中存在,編譯完成時并不會有MyInt類型。

      Go語言中的基礎(chǔ)數(shù)據(jù)類型可以表示一些事物的基本屬性,但是當(dāng)我們想表達一個事物的全部或部分屬性時,這時候再用單一的基本數(shù)據(jù)類型明顯就無法滿足需求了,Go語言提供了一種自定義數(shù)據(jù)類型,可以封裝多個基本數(shù)據(jù)類型,這種數(shù)據(jù)類型叫結(jié)構(gòu)體,英文名稱struct。 也就是我們可以通過struct來定義自己的類型了。

      Go語言中通過struct來實現(xiàn)面向?qū)ο蟆?/p>

      結(jié)構(gòu)體的定義

      使用type和struct關(guān)鍵字來定義結(jié)構(gòu)體,具體代碼格式如下:

      其中:

      舉個例子,我們定義一個Person(人)結(jié)構(gòu)體,代碼如下:

      同樣類型的字段也可以寫在一行,

      這樣我們就擁有了一個person的自定義類型,它有name、city、age三個字段,分別表示姓名、城市和年齡。這樣我們使用這個person結(jié)構(gòu)體就能夠很方便的在程序中表示和存儲人信息了。

      語言內(nèi)置的基礎(chǔ)數(shù)據(jù)類型是用來描述一個值的,而結(jié)構(gòu)體是用來描述一組值的。比如一個人有名字、年齡和居住城市等,本質(zhì)上是一種聚合型的數(shù)據(jù)類型

      結(jié)構(gòu)體實例化

      只有當(dāng)結(jié)構(gòu)體實例化時,才會真正地分配內(nèi)存。也就是必須實例化后才能使用結(jié)構(gòu)體的字段。

      基本實例化

      舉個例子:

      我們通過.來訪問結(jié)構(gòu)體的字段(成員變量),例如p1.name和p1.age等。

      匿名結(jié)構(gòu)體

      在定義一些臨時數(shù)據(jù)結(jié)構(gòu)等場景下還可以使用匿名結(jié)構(gòu)體。

      創(chuàng)建指針類型結(jié)構(gòu)體

      我們還可以通過使用new關(guān)鍵字對結(jié)構(gòu)體進行實例化,得到的是結(jié)構(gòu)體的地址。 格式如下:

      從打印的結(jié)果中我們可以看出p2是一個結(jié)構(gòu)體指針。

      需要注意的是在Go語言中支持對結(jié)構(gòu)體指針直接使用.來訪問結(jié)構(gòu)體的成員。

      取結(jié)構(gòu)體的地址實例化

      使用對結(jié)構(gòu)體進行取地址操作相當(dāng)于對該結(jié)構(gòu)體類型進行了一次new實例化操作。

      p3.name = "七米"其實在底層是(*p3).name = "七米",這是Go語言幫我們實現(xiàn)的語法糖。

      結(jié)構(gòu)體初始化

      沒有初始化的結(jié)構(gòu)體,其成員變量都是對應(yīng)其類型的零值。

      使用鍵值對初始化

      使用鍵值對對結(jié)構(gòu)體進行初始化時,鍵對應(yīng)結(jié)構(gòu)體的字段,值對應(yīng)該字段的初始值。

      也可以對結(jié)構(gòu)體指針進行鍵值對初始化,例如:

      當(dāng)某些字段沒有初始值的時候,該字段可以不寫。此時,沒有指定初始值的字段的值就是該字段類型的零值。

      使用值的列表初始化

      初始化結(jié)構(gòu)體的時候可以簡寫,也就是初始化的時候不寫鍵,直接寫值:

      使用這種格式初始化時,需要注意:

      結(jié)構(gòu)體內(nèi)存布局

      結(jié)構(gòu)體占用一塊連續(xù)的內(nèi)存。

      輸出:

      【進階知識點】關(guān)于Go語言中的內(nèi)存對齊推薦閱讀:在 Go 中恰到好處的內(nèi)存對齊

      面試題

      請問下面代碼的執(zhí)行結(jié)果是什么?

      構(gòu)造函數(shù)

      Go語言的結(jié)構(gòu)體沒有構(gòu)造函數(shù),我們可以自己實現(xiàn)。 例如,下方的代碼就實現(xiàn)了一個person的構(gòu)造函數(shù)。 因為struct是值類型,如果結(jié)構(gòu)體比較復(fù)雜的話,值拷貝性能開銷會比較大,所以該構(gòu)造函數(shù)返回的是結(jié)構(gòu)體指針類型。

      調(diào)用構(gòu)造函數(shù)

      方法和接收者

      Go語言中的方法(Method)是一種作用于特定類型變量的函數(shù)。這種特定類型變量叫做接收者(Receiver)。接收者的概念就類似于其他語言中的this或者 self。

      方法的定義格式如下:

      其中,

      舉個例子:

      方法與函數(shù)的區(qū)別是,函數(shù)不屬于任何類型,方法屬于特定的類型。

      指針類型的接收者

      指針類型的接收者由一個結(jié)構(gòu)體的指針組成,由于指針的特性,調(diào)用方法時修改接收者指針的任意成員變量,在方法結(jié)束后,修改都是有效的。這種方式就十分接近于其他語言中面向?qū)ο笾械膖his或者self。 例如我們?yōu)镻erson添加一個SetAge方法,來修改實例變量的年齡。

      調(diào)用該方法:

      值類型的接收者

      當(dāng)方法作用于值類型接收者時,Go語言會在代碼運行時將接收者的值復(fù)制一份。在值類型接收者的方法中可以獲取接收者的成員值,但修改操作只是針對副本,無法修改接收者變量本身。

      什么時候應(yīng)該使用指針類型接收者

      任意類型添加方法

      在Go語言中,接收者的類型可以是任何類型,不僅僅是結(jié)構(gòu)體,任何類型都可以擁有方法。 舉個例子,我們基于內(nèi)置的int類型使用type關(guān)鍵字可以定義新的自定義類型,然后為我們的自定義類型添加方法。

      注意事項: 非本地類型不能定義方法,也就是說我們不能給別的包的類型定義方法。

      結(jié)構(gòu)體的匿名字段

      匿名字段默認(rèn)采用類型名作為字段名,結(jié)構(gòu)體要求字段名稱必須唯一,因此一個結(jié)構(gòu)體中同種類型的匿名字段只能有一個。

      嵌套結(jié)構(gòu)體

      一個結(jié)構(gòu)體中可以嵌套包含另一個結(jié)構(gòu)體或結(jié)構(gòu)體指針。

      嵌套匿名結(jié)構(gòu)體

      當(dāng)訪問結(jié)構(gòu)體成員時會先在結(jié)構(gòu)體中查找該字段,找不到再去匿名結(jié)構(gòu)體中查找。

      嵌套結(jié)構(gòu)體的字段名沖突

      嵌套結(jié)構(gòu)體內(nèi)部可能存在相同的字段名。這個時候為了避免歧義需要指定具體的內(nèi)嵌結(jié)構(gòu)體的字段。

      結(jié)構(gòu)體的“繼承”

      Go語言中使用結(jié)構(gòu)體也可以實現(xiàn)其他編程語言中面向?qū)ο蟮睦^承。

      結(jié)構(gòu)體字段的可見性

      結(jié)構(gòu)體中字段大寫開頭表示可公開訪問,小寫表示私有(僅在定義當(dāng)前結(jié)構(gòu)體的包中可訪問)。

      結(jié)構(gòu)體與JSON序列化

      JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式。易于人閱讀和編寫。同時也易于機器解析和生成。JSON鍵值對是用來保存JS對象的一種方式,鍵/值對組合中的鍵名寫在前面并用雙引號""包裹,使用冒號:分隔,然后緊接著值;多個鍵值之間使用英文,分隔。

      結(jié)構(gòu)體標(biāo)簽(Tag)

      Tag是結(jié)構(gòu)體的元信息,可以在運行的時候通過反射的機制讀取出來。 Tag在結(jié)構(gòu)體字段的后方定義,由一對反引號包裹起來,具體的格式如下:

      `key1:"value1" key2:"value2"`

      結(jié)構(gòu)體標(biāo)簽由一個或多個鍵值對組成。鍵與值使用冒號分隔,值用雙引號括起來。鍵值對之間使用一個空格分隔。 注意事項: 為結(jié)構(gòu)體編寫Tag時,必須嚴(yán)格遵守鍵值對的規(guī)則。結(jié)構(gòu)體標(biāo)簽的解析代碼的容錯能力很差,一旦格式寫錯,編譯和運行時都不會提示任何錯誤,通過反射也無法正確取值。例如不要在key和value之間添加空格。

      例如我們?yōu)镾tudent結(jié)構(gòu)體的每個字段定義json序列化時使用的Tag:

      為什么要使用 Go 語言?Go 語言的優(yōu)勢在哪里

      1. 保留但大幅度簡化指針

      Go語言保留著C中值和指針的區(qū)別,但是對于指針繁瑣用法進行了大量的簡化,引入引用的概念。所以在Go語言中,你幾乎不用擔(dān)心會因為直接操作內(nèi)寸而引起各式各樣的錯誤。

      2. 多參數(shù)返回

      還記得在C里面為了回饋多個參數(shù),不得不開辟幾段指針傳到目標(biāo)函數(shù)中讓其操作么?在Go里面這是完全不必要的。而且多參數(shù)的支持讓Go無需使用繁瑣的exceptions體系,一個函數(shù)可以返回期待的返回值加上error,調(diào)用函數(shù)后立刻處理錯誤信息,清晰明了。

      3. Array,slice,map等內(nèi)置基本數(shù)據(jù)結(jié)構(gòu)

      如果你習(xí)慣了Python中簡潔的list和dict操作,在Go語言中,你不會感到孤單。一切都是那么熟悉,而且更加高效。如果你是C++程序員,你會發(fā)現(xiàn)你又找到了STL的vector 和 map這對朋友。

      4. Interface

      Go語言最讓人贊嘆不易的特性,就是interface的設(shè)計。任何數(shù)據(jù)結(jié)構(gòu),只要實現(xiàn)了interface所定義的函數(shù),自動就implement了這個interface,沒有像Java那樣冗長的class申明,提供了靈活太多的設(shè)計度和OO抽象度,讓你的代碼也非常干凈。千萬不要以為你習(xí)慣了Java那種一條一條加implements的方式,感覺還行,等接口的設(shè)計越來越復(fù)雜的時候,無數(shù)Bug正在后面等著你。

      同時,正因為如此,Go語言的interface可以用來表示任何generic的東西,比如一個空的interface,可以是string可以是int,可以是任何數(shù)據(jù)類型,因為這些數(shù)據(jù)類型都不需要實現(xiàn)任何函數(shù),自然就滿足空interface的定義了。加上Go語言的type assertion,可以提供一般動態(tài)語言才有的duck typing特性, 而仍然能在compile中捕捉明顯的錯誤。

      5. OO

      Go語言本質(zhì)上不是面向?qū)ο笳Z言,它還是過程化的。但是,在Go語言中, 你可以很輕易的做大部分你在別的OO語言中能做的事,用更簡單清晰的邏輯。是的,在這里,不需要class,仍然可以繼承,仍然可以多態(tài),但是速度卻快得多。因為本質(zhì)上,OO在Go語言中,就是普通的struct操作。

      6. Goroutine

      這個幾乎算是Go語言的招牌特性之一了,我也不想多提。如果你完全不了解Goroutine,那么你只需要知道,這玩意是超級輕量級的類似線程的東西,但通過它,你不需要復(fù)雜的線程操作鎖操作,不需要care調(diào)度,就能玩轉(zhuǎn)基本的并行程序。在Go語言里,觸發(fā)一個routine和erlang spawn一樣簡單。基本上要掌握Go語言,以Goroutine和channel為核心的內(nèi)存模型是必須要懂的。不過請放心,真的非常簡單。

      7. 更多現(xiàn)代的特性

      和C比較,Go語言完全就是一門現(xiàn)代化語言,原生支持的Unicode, garbage collection, Closures(是的,和functional programming language類似), function是first class object,等等等等。

      看到這里,你可能會發(fā)現(xiàn),我用了很多輕易,簡單,快速之類的形容詞來形容Go語言的特點。我想說的是,一點都不夸張,連Go語言的入門學(xué)習(xí)到提高,都比別的語言門檻低太多太多。在大部分人都有C的背景的時代,對于Go語言,從入門到能夠上手做項目,最多不過半個月。Go語言給人的感覺就是太直接了,什么都直接,讀源代碼直接,寫自己的代碼也直接。


      新聞標(biāo)題:go語言type go語言type理解
      文章位置:http://www.ef60e0e.cn/article/docgcpp.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        濮阳县| 沂水县| 甘泉县| 兰考县| 安远县| 枝江市| 景宁| 滕州市| 涟源市| 博湖县| 安龙县| 宝坻区| 金湖县| 沈丘县| 盐源县| 龙岩市| 东港市| 甘洛县| 肥西县| 广州市| 漠河县| 天津市| 南雄市| 香格里拉县| 九江县| 子长县| 老河口市| 蒙城县| 桑日县| 乡城县| 阿坝县| 乌拉特前旗| 新巴尔虎左旗| 公主岭市| 三亚市| 临武县| 仙桃市| 宁陕县| 门源| 长白| 云龙县|