中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang怎么自定義類型和方法集

發布時間:2023-02-24 16:56:52 來源:億速云 閱讀:122 作者:iii 欄目:開發技術

這篇文章主要介紹“Golang怎么自定義類型和方法集”,在日常操作中,相信很多人在Golang怎么自定義類型和方法集問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Golang怎么自定義類型和方法集”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

我們先以一個謎題開頭練練手:

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

請問上述代碼會輸出什么:

1.編譯錯誤

2.運行時panic

3.{}

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

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

$ go run customize.go
 
{}

是不是很意外,MyTime就是time.Time,理論上應該也實現了json.Marshaler,為什么輸出的是空的呢?

實際上這是最近某個群友遇到的問題,乍一看像是golang的bug,但其實還是沒掌握語言的基本規則。

在深入下去之前,我們先問自己兩個問題:

  • MyTime 真的是 Time 類型嗎?

  • MyTime 真的實現了 json.Marshaler 嗎?

對于問題1,只需要引用spec里的說明即可:

A named type is always different from any other type.

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

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

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

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

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

運行結果:

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

現在問題2也有答案了:MyTime沒有實現json.Marshaler。

那么對于一個沒有實現json.Marshaler的類型,json是怎么序列化的呢?這里就不賣關子了,文檔里有寫,對于沒實現Marshaler的類型,默認的流程使用反射獲取所有非export的字段,然后依次序列化,我們再看看time的結構:

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
}

里面都是非公開字段,所以直接序列化后整個結果就是{}。當然,Time類型自己重新實現了json.Marshaler,所以可以正常序列化成我們期望的值。

而我們的MyTime沒有實現整個接口,所以走了默認的序列化流程。

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

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

方法一是使用type alias:

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

類型別名自如其名,就是創建了一個類型A的別名而沒有定義任何新類型(注意那兩行改動)。現在MyTime就是Time了,自然也可以直接利用Time的MarshalJSON。

方法二,使用內嵌類型:

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

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

如果我實在需要派生出一種新的類型呢,通常在我們寫一個通用模塊的時候需要隱藏實現的細節,所以想要對原始類型進行一定的包裝,這時該怎么辦呢?

實際上我們可以讓MyTime重新實現json.Marshaler:

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

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

不管哪一種方案,都可以解決問題,根據自己的實際需求做選擇即可。

到此,關于“Golang怎么自定義類型和方法集”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临桂县| 昆明市| 莱阳市| 正阳县| 昌乐县| 婺源县| 克什克腾旗| 岳西县| 吉木萨尔县| 琼结县| 珲春市| 甘谷县| 蚌埠市| 潼南县| 高台县| 读书| 泰来县| 嘉鱼县| 桂平市| 贡觉县| 紫阳县| 易门县| 洱源县| 阿克苏市| 四会市| 阳朔县| 福建省| 岳西县| 高阳县| 沙坪坝区| 叙永县| 丽水市| 沁水县| 嘉义市| 湘潭市| 庆安县| 宜宾市| 永康市| 吉木乃县| 大石桥市| 简阳市|