首頁 > 軟體

一文帶你瞭解Go語言中的型別斷言和型別轉換

2022-09-18 22:00:13

Go中,型別斷言和型別轉換是一個令人困惑的事情,他們似乎都在做同樣的事情。

下面是一個型別斷言的例子:

var greeting interface{} = "hello world" 
greetingStr := greeting.(string)

接著看一個型別轉換的例子:

greeting := []byte("hello world")
greetingStr := string(greeting)

最明顯的不同點是他們具有不同的語法(variable.(type) vs type(variable) )。接下來,我們進一步去研究。

型別斷言

顧名思義,型別斷言用於斷言變數是屬於某種型別。型別斷言只能發生在interface{}型別上。

上面型別斷言的例子,greeting是一個interface{}型別,我們為其分配了一個字串。現在,我們可以認為greeting實際上是一個string,但是對外展示的是一個interface{}

如果我們想獲取greeting的原始型別,那麼我們可以斷言它是個string,並且此斷言操作會返回其string型別。

這意味著在做型別斷言的時候,我們應該知道任何變數的基礎型別。但是情況並非總是這樣的,這就是為什麼型別斷言操作實際上還返回了第二個可選值的原因。

var greeting interface{} = "42" greetingStr, ok := greeting.(string)

第二個值是一個布林值,如果斷言正確,返回 true ,否則返回 false。

另外,型別斷言是在程式執行時執行。

型別判斷

型別判斷是一個很實用的構造。當你不確定interface{}真正型別的時候,可以使用它。

var greeting interface{} = 42

switch g := greeting.(type) {
  case string:
    fmt.Println("g is a string with length", len(g))
  case int:
    fmt.Println("g is an integer, whose value is", g)
  default:
    fmt.Println("I don't know what g is")
}

為什麼需要斷言

在上面的例子中,我們似乎在將greetinginterface{}轉換成int型別或者string型別。但是greeting的型別是固定,並且和初始化期間宣告時的內容一樣。

當我們把greeting分配給interface{}型別的時候,請勿修改其原始型別。同樣,當我們斷言型別的時候,我們只是使用了原始型別功能,而不是使用interface公開的有限方法。

型別轉換

首先,我們花點時間瞭解一下什麼是 “型別”。在 Go 每種型別都定義了兩件事:

  • 變數的儲存方式 (儲存結構)
  • 你可以使用變數做什麼 (可以使用的方法和函數)

這裡介紹了基本型別,包括了stringint。以及一些複合型別,比如struct``map``arrayslice。 你可以從基本型別或通過建立複合型別來宣告一個新型別。

// `myInt` 是一個新型別,它的基本類型是 `int`
type myInt int

// AddOne 方法適用於 `myInt` 型別,不適用於 `int` 型別
func (i myInt) AddOne() myInt { return i + 1}

func main() {
    var i myInt = 4
    fmt.Println(i.AddOne())
}

當我們宣告一個myInt型別,我們可以將變數資料基於基本的int型別,但是如果要進行變數修改,我們可以通過myInt型別變數進行操作 (通過在myInt上面宣告一個新方法)。 由於myInt 的型別基於int,意味著他們的底層基礎型別是一樣的。因此這些型別的變數可以相互轉換。

var i myInt = 4
originalInt := int(i)

上面i的型別是myInt,originalInt的型別是int

什麼時候使用型別轉換

只有當基礎資料結構型別相同,型別之間才可以相互轉換。來看一個使用struct例子。

type person struct {
    name string
    age int
}

type child struct {
    name string
    age int
}

type pet {
  name string
}

func main() {
    bob := person{
        name: "bob",
        age: 15,
        }
  babyBob := child(bob)
  // "babyBob := pet(bob)" 會導致編譯錯誤
    fmt.Println(bob, babyBob)
}

在這裡,person 和 child 擁有相同的資料結構,即:

struct {
    name string
    age int
}

因此他們可以相互轉換。 type可用於宣告具有相同資料結構的多種型別。 這只是意味著childperson基於相同的資料結構 (類似於之前的intmyInt)。

型別為什麼稱為轉換

就像上面說的,雖然不同型別的基礎結構可能相同,但是他們可能也具有不同的限制和方法。當我們從一種型別轉換成另一種型別時,會改變對型別的處理方式,而不是像型別斷言那樣僅公開其基礎型別,這就是他們本質的差別。

如果嘗試去轉換錯誤的型別,型別轉換會提示編譯錯誤,這和型別斷言所提供的執行時通過返回值判斷錯誤,完全相反。

型別結論

型別斷言和型別轉換有著比語法層面上更根本的區別。它還強調了在Go中介面型別 (interface) 和非介面型別之間的區別。 介面型別沒有任何資料結構,而是公開了已有的具體型別 (具有底層資料結構) 的一些方法。

型別斷言引出了介面的具體型別,而型別轉換改變了在具有相同資料結構的兩個具體型別之間使用變數的方式。

到此這篇關於一文帶你瞭解Go語言中的型別斷言和型別轉換的文章就介紹到這了,更多相關Go型別斷言 型別轉換內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com