您好,登錄后才能下訂單哦!
go語言中的type是什么?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
type是go語法里的重要而且常用的關鍵字,type絕不只是對應于C/C++中的typedef。type又有兩種使用方式,一種是類型別名,一種是類型定義,是不是熟悉的C語言(define和typedef)味道?
類型定義
type Student struct { name String age int } type I int
類型別名
type Sdt = Student type I = int
type有如下幾種用法:
定義結構體
定義接口
類型定義
類型別名
類型查詢
定義結構體
結構體是用戶自定義的一種抽象的數據結構,golang中struct類似于java語言中的class, 在程序設計中,有著舉足輕重的地位。結構體的用法,將會在struct關鍵字中詳細的介紹。下邊來看一下定義一個結構體的語法格式:
type name struct { Field1 dataType Field2 dataType Field3 dataType }
定義接口
接口相關知識點,將會在interface關鍵字中詳細介紹,下邊來看一段定義接口的語法格式:
type name interface{ Read() Write() }
類型定義
使用類型定義定義出來的類型與原類型不相同,所以不能使用新類型變量賦值給原類型變量,除非使用強制類型轉換。下面來看一段示例代碼,根據string類型,定義一種新的類型,新類型名稱是name:
type name string
為什么要使用類型定義呢?
類型定義可以在原類型的基礎上創造出新的類型,有些場合下可以使代碼更加簡潔,如下邊示例代碼:
package main import ( "fmt" ) // 定義一個接收一個字符串類型參數的函數類型 type handle func(str string) // exec函數,接收handle類型的參數 func exec(f handle) { f("hello") } func main() { // 定義一個函數類型變量,這個函數接收一個字符串類型的參數 var p = func(str string) { fmt.Println("first", str) } exec(p) // 匿名函數作為參數直接傳遞給exec函數 exec(func(str string) { fmt.Println("second", str) }) }
輸出信息是:
first hello second hello
上邊的示例是類型定義的一種簡單應用場合,如果不使用類型定義,那么想要實現上邊示例中的功能,應該怎么書寫這段代碼呢?
// exec函數,接收handle類型的參數 func exec(f func(str string)) { f("hello") }
exec函數中的參數類型,需要替換成func(str string)了,咋一看去也不復雜,但是假如exec接收一個需要5個參數的函數變量呢?是不是感覺參數列表就會很長了。
func exec(f func(str string, str2 string, num int, money float64, flag bool)) { f("hello") }
從上邊的代碼可以發現,exec函數的參數列表可讀性變差了。下邊再來看看使用類型定義是怎么實現這個功能:
package main import ( "fmt" ) // 定義一個需要五個參數的函數類型 type handle func(str string, str2 string, num int, money float64, flag bool) // exec函數,接收handle類型的參數 func exec(f handle) { f("hello", "world", 10, 11.23, true) } func demo(str string, str2 string, num int, money float64, flag bool) { fmt.Println(str, str2, num, money, flag) } func main() { exec(demo) }
類型別名
類型別名這個特性在golang1.9中引入。使用類型別名定義出來的類型與原類型一樣,即可以與原類型變量互相賦值,又擁有了原類型的所有方法集。給strng類型取一個別名,別名名稱是name:
type name = string
類型別名與類型定義不同之處在于,使用類型別名需要在別名和原類型之間加上賦值符號(=);使用類型別名定義的類型與原類型等價,而使用類型定義出來的類型是一種新的類型。
如下邊示例:
package main import ( "fmt" ) type a = string type b string func SayA(str a) { fmt.Println(str) } func SayB(str b) { fmt.Println(str) } func main() { var str = "test" SayA(str) //錯誤參數傳遞,str是字符串類型,不能賦值給b類型變量 SayB(str) }
這段代碼在編譯時會出現如下錯誤:
.\main.go:21:6: cannot use str (type string) as type b in argument to SayB
從錯誤信息可知,str為字符串類型,不能當做b類型參數傳入SayB函數中。而str卻可以當做a類型參數傳入到SayA函數中。由此可見,使用類型別名定義的類型與原類型一致,而類型定義定義出來的類型,是一種新的類型。
給類型別名新增方法,會添加到原類型方法集中
給類型別名新增方法后,原類型也能使用這個方法。下邊請看一段示例代碼:
package main import ( "fmt" ) // 根據string類型,定義類型S type S string func (r *S) Hi() { fmt.Println("S hi") } // 定義S的類型別名為T type T = S func (r *T) Hello() { fmt.Println("T hello") } // 函數參數接收S類型的指針變量 func exec(obj *S) { obj.Hello() obj.Hi() } func main() { t := new(T) s := new(S) exec(s) // 將T類型指針變量傳遞給S類型指針變量 exec(t) }
輸出信息是:
T hello S hi T hello S hi
上邊的示例中,S是原類型,T是S類型別名。在給T增加了Hello方法后,S類型的變量也可以使用Hello方法。說明給類型別名新增方法后,原類型也能使用這個方法。從示例中可知,變量t可以賦值給S類型變量s,所以類型別名是給原類型取了一個小名,本質上沒有發生任何變化。
類型別名,只能對同一個包中的自定義類型產生作用。舉個例子,golang sdk中有很多個包,是不是我們可以使用類型別名,給sdk包中的結構體類型新增方法呢?答案是:不行。請牢記一點:類型別名,只能對包內的類型產生作用,對包外的類型采用類型別名,在編譯時將會提示如下信息:
cannot define new methods on non-local type string
類型查詢
類型查詢,就是根據變量,查詢這個變量的類型。為什么會有這樣的需求呢?goalng中有一個特殊的類型interface{},這個類型可以被任何類型的變量賦值,如果想要知道到底是哪個類型的變量賦值給了interface{}類型變量,就需要使用類型查詢來解決這個需求,示例代碼如下:
package main import ( "fmt" ) func main() { // 定義一個interface{}類型變量,并使用string類型值”abc“初始化 var a interface{} = "abc" // 在switch中使用 變量名.(type) 查詢變量是由哪個類型數據賦值。 switch v := a.(type) { case string: fmt.Println("字符串") case int: fmt.Println("整型") default: fmt.Println("其他類型", v) } }
如果使用.(type)查詢類型的變量不是interface{}類型,則在編譯時會報如下錯誤:
cannot type switch on non-interface value a (type string)
如果在switch以外地方使用.(type),則在編譯時會提示如下錯誤:
use of .(type) outside type switch
所以,使用type進行類型查詢時,只能在switch中使用,且使用類型查詢的變量類型必須是interface{}
看完上述內容,你們對go語言中的type有進一步的了解嗎?如果還想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。