最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang拾遺之自定義類型和方法集詳解

 更新時(shí)間:2023年02月20日 15:27:21   作者:apocelipes  
golang拾遺主要是用來(lái)記錄一些遺忘了的、平時(shí)從沒(méi)注意過(guò)的golang相關(guān)知識(shí)。這篇文章主要整理了一下Golang如何自定義類型和方法集,需要的可以參考一下

golang拾遺主要是用來(lái)記錄一些遺忘了的、平時(shí)從沒(méi)注意過(guò)的golang相關(guān)知識(shí)。

很久沒(méi)更新了,我們先以一個(gè)謎題開頭練練手:

package main
 
import (
    "encoding/json"
    "fmt"
    "time"
)
 
type MyTime time.Time
 
func main() {
    myTime := MyTime(time.Now()) // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
    res, err := json.Marshal(myTime)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(res))
}

請(qǐng)問(wèn)上述代碼會(huì)輸出什么:

1.編譯錯(cuò)誤

2.運(yùn)行時(shí)panic

3.{}

4."2022-07-20T20:30:00.135693011+08:00"

很多人一定會(huì)選4吧,然而答案是3:

$ go run customize.go
 
{}

是不是很意外,MyTime就是time.Time,理論上應(yīng)該也實(shí)現(xiàn)了json.Marshaler,為什么輸出的是空的呢?

實(shí)際上這是最近某個(gè)群友遇到的問(wèn)題,乍一看像是golang的bug,但其實(shí)還是沒(méi)掌握語(yǔ)言的基本規(guī)則。

在深入下去之前,我們先問(wèn)自己兩個(gè)問(wèn)題:

  • MyTime 真的是 Time 類型嗎?
  • MyTime 真的實(shí)現(xiàn)了 json.Marshaler 嗎?

對(duì)于問(wèn)題1,只需要引用spec里的說(shuō)明即可:

A named type is always different from any other type.

https://go.dev/ref/spec#Type_identity

意思是說(shuō),只要是type定義出來(lái)的類型,都是不同的(type alias除外),即使他們的underlying type是一樣的,也是兩個(gè)不同的類型。

那么問(wèn)題1的答案就知道了,顯然MyTime不是time.Time。

既然MyTime不是Time,那它是否能用Time類型的method呢?畢竟MyTime的基底類型是Time呀。我們寫段代碼驗(yàn)證下:

package main
 
import (
    "fmt"
    "time"
)
 
type MyTime time.Time
 
func main() {
    myTime := MyTime(time.Now()) // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
    res, err := myTime.MarsharlJSON()
    if err != nil {
            panic(err)
    }
    fmt.Println(string(res))
}

運(yùn)行結(jié)果:

# command-line-arguments
./checkoutit.go:12:24: myTime.MarsharlJSON undefined (type MyTime has no field or method MarsharlJSON)

現(xiàn)在問(wèn)題2也有答案了:MyTime沒(méi)有實(shí)現(xiàn)json.Marshaler。

那么對(duì)于一個(gè)沒(méi)有實(shí)現(xiàn)json.Marshaler的類型,json是怎么序列化的呢?這里就不賣關(guān)子了,文檔里有寫,對(duì)于沒(méi)實(shí)現(xiàn)Marshaler的類型,默認(rèn)的流程使用反射獲取所有非export的字段,然后依次序列化,我們?cè)倏纯磘ime的結(jié)構(gòu):

type Time struct {
        // wall and ext encode the wall time seconds, wall time nanoseconds,
        // and optional monotonic clock reading in nanoseconds.
        //
        // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
        // a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
        // The nanoseconds field is in the range [0, 999999999].
        // If the hasMonotonic bit is 0, then the 33-bit field must be zero
        // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
        // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
        // unsigned wall seconds since Jan 1 year 1885, and ext holds a
        // signed 64-bit monotonic clock reading, nanoseconds since process start.
        wall uint64
        ext  int64
 
        // loc specifies the Location that should be used to
        // determine the minute, hour, month, day, and year
        // that correspond to this Time.
        // The nil location means UTC.
        // All UTC times are represented with loc==nil, never loc==&utcLoc.
        loc *Location
}

里面都是非公開字段,所以直接序列化后整個(gè)結(jié)果就是{}。當(dāng)然,Time類型自己重新實(shí)現(xiàn)了json.Marshaler,所以可以正常序列化成我們期望的值。

而我們的MyTime沒(méi)有實(shí)現(xiàn)整個(gè)接口,所以走了默認(rèn)的序列化流程。

所以我們可以得出一個(gè)重要的結(jié)論:從某個(gè)類型A派生出的類型B,B并不能獲得A的方法集中的任何一個(gè)。

想要B擁有A的所有方法也不是不行,但得和type B A這樣的形式說(shuō)再見了。

方法一是使用type alias:

- type MyTime time.Time
+ type MyTime = time.Time
 
func main() {
-   myTime := MyTime(time.Now()) // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
+   var myTime MyTime = time.Now() // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
    res, err := json.Marshal(myTime)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(res))
}

類型別名自如其名,就是創(chuàng)建了一個(gè)類型A的別名而沒(méi)有定義任何新類型(注意那兩行改動(dòng))?,F(xiàn)在MyTime就是Time了,自然也可以直接利用Time的MarshalJSON。

方法二,使用內(nèi)嵌類型:

- type MyTime time.Time
+ type MyTime struct {
+     time.Time
+ }
 
func main() {
-   myTime := MyTime(time.Now()) // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
+   myTime := MyTime{time.Now}
    res, err := myTime.MarsharlJSON()
    if err != nil {
            panic(err)
    }
    fmt.Println(string(res))
}

通過(guò)將Time嵌入MyTime,MyTime也可以獲得Time類型的方法集。更具體的可以看我之前寫的另一篇文章:golang拾遺:嵌入類型

如果我實(shí)在需要派生出一種新的類型呢,通常在我們寫一個(gè)通用模塊的時(shí)候需要隱藏實(shí)現(xiàn)的細(xì)節(jié),所以想要對(duì)原始類型進(jìn)行一定的包裝,這時(shí)該怎么辦呢?

實(shí)際上我們可以讓MyTime重新實(shí)現(xiàn)json.Marshaler:

type MyTime time.Time
 
func (m MyTime) MarshalJSON() ([]byte, error) {
    // 我圖方便就直接復(fù)用Time的了
    return time.Time(m).MarshalJSON()
}
 
func main() {
    myTime := MyTime(time.Now()) // 假設(shè)獲得的時(shí)間是 2022年7月20日20:30:00,時(shí)區(qū)UTC+8
    res, err := myTime.MarsharlJSON()
    if err != nil {
            panic(err)
    }
    fmt.Println(string(res))
}

這么做看上去違反了DRY原則,其實(shí)未必,這里只是示例寫的爛而已,真實(shí)場(chǎng)景下往往對(duì)派生出來(lái)的自定義類型進(jìn)行一些定制,因此序列化函數(shù)里會(huì)有額外的一些操作,這樣就和DRY不沖突了。

不管哪一種方案,都可以解決問(wèn)題,根據(jù)自己的實(shí)際需求做選擇即可。

總結(jié)

總結(jié)一下,一個(gè)派生自A的自定義類型B,它的方法集中的方法只有兩個(gè)來(lái)源:

  • 直接定義在B上的那些方法
  • 作為嵌入類型包含在B里的其他類型的方法

而A的方法是不存在在B中的。

如果是從一個(gè)匿名類型派生的自定義類型B(type B struct {a, b int}),那么B的方法集中的方法只有一個(gè)來(lái)源:

直接定義在B上的那些方法

還有最重要的,如果兩個(gè)類型名字不同,即使它們的結(jié)構(gòu)完全相同,也是兩個(gè)不同的類型。

這些邊邊角角的知識(shí)很容易被遺忘,但還是有機(jī)會(huì)在工作中遇到的,記牢了可以省很多事。

到此這篇關(guān)于Golang拾遺之自定義類型和方法集詳解的文章就介紹到這了,更多相關(guān)Golang自定義類型 方法集內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang實(shí)現(xiàn)微信公眾號(hào)后臺(tái)接入的示例代碼

    Golang實(shí)現(xiàn)微信公眾號(hào)后臺(tái)接入的示例代碼

    這篇文章主要介紹了Golang實(shí)現(xiàn)微信公眾號(hào)后臺(tái)接入的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 使用Golang開發(fā)一個(gè)簡(jiǎn)易版shell

    使用Golang開發(fā)一個(gè)簡(jiǎn)易版shell

    這篇文章主要為大家詳細(xì)介紹了如何使用Golang開發(fā)一個(gè)簡(jiǎn)易版shell,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • go語(yǔ)言中fallthrough的用法說(shuō)明

    go語(yǔ)言中fallthrough的用法說(shuō)明

    這篇文章主要介紹了go語(yǔ)言中fallthrough的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • Go語(yǔ)言網(wǎng)站使用異步編程和Goroutine提高Web的性能

    Go語(yǔ)言網(wǎng)站使用異步編程和Goroutine提高Web的性能

    作為一門現(xiàn)代化編程語(yǔ)言,Go語(yǔ)言提供了強(qiáng)大的異步編程能力,使得程序員可以以更高效的方式處理并發(fā)任務(wù),在Go語(yǔ)言中,使用Goroutine在單個(gè)進(jìn)程中實(shí)現(xiàn)多任務(wù)并行處理,以及如何使用協(xié)程池來(lái)進(jìn)一步提高Web服務(wù)器的處理能力,
    2024-01-01
  • Go語(yǔ)言到底有沒(méi)有引用傳參(對(duì)比 C++ )

    Go語(yǔ)言到底有沒(méi)有引用傳參(對(duì)比 C++ )

    這篇文章主要介紹了Go 到底有沒(méi)有引用傳參(對(duì)比 C++ ),需要的朋友可以參考下
    2017-09-09
  • Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的方法實(shí)例

    Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的方法實(shí)例

    將一個(gè)值從一種類型轉(zhuǎn)換到另一種類型,便發(fā)生了類型轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 自己動(dòng)手用Golang實(shí)現(xiàn)約瑟夫環(huán)算法的示例

    自己動(dòng)手用Golang實(shí)現(xiàn)約瑟夫環(huán)算法的示例

    這篇文章主要介紹了自己動(dòng)手用Golang實(shí)現(xiàn)約瑟夫環(huán)算法的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Goland 關(guān)閉自動(dòng)移除未使用的包操作

    Goland 關(guān)閉自動(dòng)移除未使用的包操作

    這篇文章主要介紹了Goland 關(guān)閉自動(dòng)移除未使用的包操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go實(shí)現(xiàn)一個(gè)輕量級(jí)并發(fā)任務(wù)調(diào)度器(支持限速)

    Go實(shí)現(xiàn)一個(gè)輕量級(jí)并發(fā)任務(wù)調(diào)度器(支持限速)

    本文主要介紹了Go實(shí)現(xiàn)一個(gè)輕量級(jí)并發(fā)任務(wù)調(diào)度器(支持限速),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04
  • 詳解go中的defer鏈如何被遍歷執(zhí)行

    詳解go中的defer鏈如何被遍歷執(zhí)行

    為了在退出函數(shù)前執(zhí)行一些資源清理的操作,例如關(guān)閉文件、釋放連接、釋放鎖資源等,會(huì)在函數(shù)里寫上多個(gè)defer語(yǔ)句,多個(gè)_defer 結(jié)構(gòu)體形成一個(gè)鏈表,G 結(jié)構(gòu)體中某個(gè)字段指向此鏈表,那么go中的defer鏈如何被遍歷執(zhí)行,本文將給大家詳細(xì)的介紹,感興趣的朋友可以參考下
    2024-01-01

最新評(píng)論

驻马店市| 荔波县| 伊金霍洛旗| 四平市| 大理市| 南京市| 甘洛县| 唐海县| 翼城县| 磴口县| 义乌市| 东源县| 扎囊县| 沙湾县| 思南县| 喀喇| 石河子市| 三穗县| 西充县| 天门市| 溆浦县| 阿尔山市| 盱眙县| 福安市| 霸州市| 桦川县| 武清区| 尼木县| 吉木乃县| 岗巴县| 佳木斯市| 宜兰市| 营山县| 吴旗县| 麻城市| 迭部县| 柘城县| 思南县| 当雄县| 黔西| 从化市|