【新人系列】Golang 入門(十五):類型斷言

? 個人博客:https://blog.csdn.net/Newin2020?type=blog
📝 專欄地址:https://blog.csdn.net/newin2020/category_12898955.html
📣 專欄定位:為 0 基礎剛入門 Golang 的小伙伴提供詳細的講解,也歡迎大佬們一起交流~
📚 專欄簡介:在這個專欄,我將帶著大家從 0 開始入門 Golang 的學習。在這個 Golang 的新人系列專欄下,將會總結 Golang 入門基礎的一些知識點,并由淺入深的學習這些知識點,方便大家快速入門學習~
?? 如果有收獲的話,歡迎點贊 👍 收藏 📁 關注,您的支持就是我創作的最大動力 💪

1. 快速了解

在 Go 語言(Golang)中,斷言(Type Assertion)是一種用于在運行時檢查接口值實際保存的具體類型,并獲取對應類型值的機制。

例如,下面 add 函數中入參被定義成了空接口的類型,因此我們可以針對入參進行類型斷言,通過 a.(int) 的方式來判斷入參的類型是否為 int 類型。

func add(a, b interface{}) interface{} {ai, ok := a.(int)if !ok {panic("not int type")}bi, _ := b.(int)return ai + bi
}func main() {a := 1b := 2fmt.Println(add(a,b))
}

當然,我們可以利用 switch 語法來適應不同類型的斷言:

func add(a, b interface{}) interface{} {switch a.(type) {case int :ai, _ := a.(int)bi, _ := b.(int)return ai + bicase int32:ai, _ := a.(int32)bi, _ := b.(int32)return ai + bicase float64:af, _ := a.(float64)bf, _ := b.(float64)return af + bfdefault:panic("not supported type")}
}func main() {fmt.Println(add(1,2))fmt.Println(add(1.2,2.3))
}

而從前面的接口篇章可以得知,接口可以分為「空接口」和「非空接口」兩類。
相對于接口這種「抽象類型」,int、string、slice 等等都可以被稱為「具體類型」。

在這里插入圖片描述

  • 類型斷言作用于接口值之上,可以是空接口或非空接口
  • 斷言的目標類型,可以是具體類型或非空接口類型

這樣,就組合出了四種類型斷言,接下來我們就逐一看看它們究竟是怎樣 “斷言” 的。

在這里插入圖片描述

2 空接口.(具體類型)

var e interface {}r, ok := e.(*os.File)

上面的代碼中 e.(*os.File) 是要判斷 e 的動態類型是否為 *os.File,而這只需要確定 _type 是否指向 *os.File 的類型元數據即可。

在這里插入圖片描述

在 go 語言里每種類型的類型元數據都是全局唯一的,如果像下面這樣給 e 賦值,那么 e 的動態值就是 f,動態類型就是 *os.File。

所以下面代碼會斷言成功,ok 為 true,r 被賦值為 e 的動態值。

var e interface {}f, _ := os.Open("output.txt")
e = fr, ok := e.(*os.File)

在這里插入圖片描述

而如果像下面這樣賦值,e 的動態類型就是 string 類型,那么類型斷言就會失敗。

此時 ok 就為 false,r 會被賦值為 *os.File 的類型零值 nil。

var e interface {}f  := "output"
e = fr, ok := e.(*os.File)

在這里插入圖片描述

3 非空接口.(具體類型)

var rw io.ReadWriterr, ok := rw.(*os.File)

上面代碼中 rw.(*os.File) 是要判斷 rw 的動態類型是否為 *os.File。

在這里插入圖片描述

之前的篇章中,我們也介紹過,程序中用到的 itab 結構體都會緩存起來,可以通過接口類型和動態類型組合起來的 key,查找到對應的 itab 指針。

所以這里的類型斷言只需要一次比較就能完成,只要看 tab = &itab 是否指向這個 itab 結構體即可

在這里插入圖片描述

如果 rw 像下面代碼這樣賦值,那么它的動態值就是 f,動態類型就是 *os.File。

var rw io.ReadWriterf, _ := os.Open("output.txt")
rw = fr, ok := rw.(*os.File)

所以 tab 指向下面圖中第二塊部分的這個 itab 結構體,因此類型斷言成功,ok 為 true 且 r 被賦值為 rw 的動態值。

在這里插入圖片描述

然而,如果 rw 動態類型不是 *os.File。

var rw io.ReadWriterf, _ := output{name: "output"}
rw = fr, ok := rw.(*os.File)

那么此時 tab 就指向下面圖中第一塊部分,而不是圖中第二塊部分的地方。所以類型斷言就會失敗,ok 為 false 且 r 會被置為 *os.File 的類型零值 nil。

在這里插入圖片描述

4. 空接口.(非空接口)

var e interface {}rw, ok := e.(ioReadWriter)

e.(ioReadWriter) 是要判斷 e 的動態類型是否實現了 io.ReadWriter 接口,當然之前的篇章中我們已經介紹過類型關聯的方法列表該去哪里找了。

在這里插入圖片描述

如果像下面代碼中 e 這樣賦值,那么它的動態值就是 f,動態類型就是 *os.File。

var e interface {}f, _ := os.Open("output.txt")
e = frw, ok := e.(ioReadWriter)

雖然 *os.File 元數據后面可以找到類型關聯的方法元數據數組,但也不必每次都去檢查這里是否有對應接口要求的所有方法。

在這里插入圖片描述

因為存在 itab 緩存,所以可以先去 itab 緩存中查找一下。若沒有 io.ReadWriter 和 *os.File 對應的 itab 結構體,再去檢查 *os.File 的方法列表也不遲。

在這里插入圖片描述

值得強調的是,就算能夠從緩存中查找到對應的 itab 指針,也要進一步判斷 itab.fun[0] 是否等于 0。

在這里插入圖片描述

這是因為斷言失敗的類型組合,其對應的 itab 結構體也會被緩存起來,只是會把 itab.fun[0] 置為 0,用以表示這里的動態類型并沒有實現對應的接口。

這樣以后再遇到同種類型斷言時,就不用再去檢查方法列表了,可以直接斷言失敗。

在這里插入圖片描述

而我們上面這個例子中,類型斷言是成功的,所以 ok 為 true,而 rw 就是一個 io.ReadWriter 類型的變量,其動態值與 e 相同,tab 就指向下面這樣一個 itab 結構體。

在這里插入圖片描述

但如果 e 被賦值為一個字符串,那么它的動態類型就是 string,并沒有實現要求的 Read 和 Write 方法,所以對應的 itab 中 fun[0] 的值為 0,并且會被添加到 itab 緩存中。

var e interface {}f, _ := "output"
e = frw, ok := e.(ioReadWriter)

在這里插入圖片描述

因此這里斷言失敗,ok 為 false 且 rw 為 io.ReadWriter 的類型零值 nil。

5. 非空接口.(非空接口)

var w io.Writerrw, ok := w.(io.ReadWriter)

w.(io.ReadWriter) 是要判斷 w 存儲的動態類型是否實現了 io.ReadWriter 接口,w 是 io.Writer 類型,接口要求一個 Write 方法,而 io.ReadWriter 接口要求實現 Read 和 Write 兩個方法。

在這里插入圖片描述

如果 w 像下面的代碼這樣賦值,其動態值就是 f。

var w io.Writerf, _ := os.Open("output.txt")
w = frw, ok := w.(io.ReadWriter)

tab 指向下圖這樣一個 itab 結構體,要確定 *os.File 是否實現了 io.ReadWriter 接口,同樣會先去 itab 緩存里查找這個組合對應的 itab 指針。

在這里插入圖片描述

若存在,且 itabfun[0] 不等于 0,則斷言成功;若不存在,再去檢查 *os.File 的方法列表,并緩存 itab 信息。

而在這里的代碼中,斷言是成功的,即 ok 為 true 且 rw 為 io.ReadWriter 類型的變量,動態值與 w 相同,而 tab 指向下面這個 itab 結構體。

在這里插入圖片描述

如果我們自定義一個 output 類型,并且 *output 類型只實現了 io.Writer 接口,并沒有實現 io.ReadWriter 接口。

type output struct {name string
}func (o *output) Write(b []byte) (n int, err error) {return len(o.name), nil
}

現在如果把這個 output 類型的變量賦值給 w,那么此時 w 的動態類型就為 *output,并沒有實現指定接口,所以 fun[0] = 0,該 itab 結構體就會被緩存起來。

var w io.Writerf, _ := output{name: "john")
w = &frw, ok := w.(io.ReadWriter)

因此,類型斷言會失敗,ok 為 false 且 rw 的 tab 和 data 均為 nil。

所以,類型斷言的關鍵是明確接口的動態類型,以及對應的類型實現了哪些方法。而明確這些的關鍵還是「類型元數據」,以及空接口與非空接口的「數據結構」。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902171.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902171.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902171.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI大模型發展現狀與MCP協議誕生的技術演進

1. 大模型能力邊界與用戶痛點(2023年) 代表模型:GPT-4(OpenAI)、Claude 3(Anthropic)、通義千問(阿里云)等展現出強大的生成能力,但存在明顯局限&#xff1a…

深入理解Linux中的線程控制:多線程編程的實戰技巧

個人主頁:chian-ocean 文章專欄-Linux 前言: POSIX線程(Pthreads) 是一種在 POSIX 標準下定義的線程庫,它為多線程編程提供了統一的接口,主要用于 UNIX 和類 UNIX 系統(如 Linux、MacOS 和 BS…

(mac)Grafana監控系統之監控Linux的Redis

Grafana安裝-CSDN博客 普羅米修斯Prometheus監控安裝(mac)-CSDN博客 1.Redis_exporter安裝 直接下載 wget https://github.com/oliver006/redis_exporter/releases/download/v1.0.3/redis_exporter-v1.0.3.linux-amd64.tar.gz 解壓 tar -xvf redis_…

鴻蒙應用元服務開發-Account Kit未成年人模式訂閱和處理用戶信息變更

一、概述 通過訂閱用戶信息變更,您可以接收有關用戶及其賬戶的重要更新。當用戶取消元服務的授權信息、注銷華為賬號時,華為賬號服務器會發送通知到元服務,元服務可以根據通知消息進行自身業務處理。 二、用戶信息變更事件介紹 三、訂閱用…

buildroot構建根文件系統報錯(已解決大部分問題)

title: buildroot構建根文件系統報錯(set FORCE_UNSAFE_CONFIGURE1) author: cbus categories: 小知識 tags:小知識 abbrlink: 53691 date: 2025-04-20 08:03:00 錯誤1 set FORCE_UNSAFE_CONFIGURE1 在使用buildroot構建根文件系統時,一切按照文檔的配置&#xff0…

7.QT-常用控件-QWidget|font|toolTip|focusPolicy|styleSheet(C++)

font API說明font()獲取當前widget的字體信息.返回QFont對象.setFont(const QFont& font)設置當前widget的字體信息. 屬性說明family字體家族.?如"楷體",“宋體”,"微軟雅?"等.pointSize字體??weight字體粗細.以數值?式表?粗細程度取值范圍為[…

通過面向目標的獎勵彌合人與機器人的靈活性差距

24年10月來自紐約大學的論文“Bridging the Human to Robot Dexterity Gap through Object-Oriented Rewards”。 直接通過人類視頻訓練機器人是機器人技術和計算機視覺領域的一個新興領域。盡管雙指機械手在雙指夾持器方面取得了顯著進展,但以這種方式讓多指機械手…

C++入門篇(下)

目錄 1、引用 1.1 引用概念 1.2 引用特性 1.3 常引用 1.4 使用場景 1.4.1 引用做參數 1.4.2 引用做返回值 1.5 引用和指針的區別 2、內聯函數 2.1 概念 2.2 特性 3、auto關鍵字 4、基于范圍的for循環 5、指針空值nullptr 5.1 C98 中的指針空值處理 5.2 C11 …

Multi-Query Attention (MQA) PyTorch 實現

和多頭注意力機制的唯一區別:K、V在不同的head之間實現了復用,而對于不同的頭,Q依然不同。 因此這里的代碼和標準多頭注意力的實現也是幾乎完全一樣: import torch import torch.nn as nn import torch.nn.functional as Fclass…

visual studio無法跳轉到函數定義、變量定義、跳轉函數位置不準問題解決

參考:https://blog.csdn.net/snakehacker/article/details/135438353 程序有時會出現大部分函數都不能準確的從頭文件中正確定位到函數定位,這是因為數據庫錯亂造成的,可以通過重構數據庫來解決,操作方法如下: 菜單欄:工具——選項 文本編輯…

Java優雅實現判空方法

在 Java 開發中,頻繁的 if (obj ! null) 判空代碼會導致代碼冗余、可讀性差,且容易遺漏判空導致 NullPointerException。以下從 語言特性、設計模式、工具類 和 編碼規范 四個維度,結合實際案例,詳解如何優雅處理空值問題。 一、…

京東百億補貼殺入外賣市場:一場關乎即時零售未來的攻防戰

當美團和餓了么在外賣市場雙雄爭霸十余年之際,京東突然以"百億補貼免傭金"的組合拳高調入場。這場看似跨界的外賣大戰,實則是互聯網巨頭對萬億級即時零售市場的生死爭奪。 外賣只是表象,即時零售才是終極戰場 京東黑板報4月10日官…

UNION和UNION ALL的主要區別

UNION和UNION ALL的主要區別在于處理重復數據和排序的方式。 UNION和UNION ALL都是SQL語言中用于合并兩個或多個SELECT語句結果集的關鍵字。它們的主要區別如下: 1、對重復結果的處理:UNION在進行表鏈接后會篩選掉重復的記錄,而UNION ALL不會…

七段碼 路徑壓縮 并查集 dfs

12.七段碼 - 藍橋云課 將七個二極管映射為 1-7 開一個二維矩陣 為 相鄰的邊連上線 edge[1][2] edge[1][6] 1;edge[2][1] edge[2][3] edge[2][7] 1;edge[3][2] edge[3][4] edge[3][7] 1;edge[4][3] edge[4][5] 1;edge[5][4] edge[5][6] edge[5][7] 1;edge[6][1…

科技如何改變世界?

技術是我們日常生活中不可或缺的一部分,以至于我們常常忘記了它的重要性。如果你正在科技領域工作,或者希望進入該領域,你可能是眾多有使命感的人之一,希望知道自己的日常工作能為社會或地球的長遠利益做出貢獻。 別再四處尋找了…

抽象的https原理簡介

前言 小明和小美是一對好朋友,他們分隔兩地,平時經常寫信溝通,但是偶然被小明發現他回給小美的信好像被人拆開看過,甚至偷偷被篡改過。 對稱加密算法 開頭的通信過程比較像HTTP服務器與客戶端的通信過程,全明文傳輸…

高級java每日一道面試題-2025年4月13日-微服務篇[Nacos篇]-Nacos如何處理網絡分區情況下的服務可用性問題?

如果有遺漏,評論區告訴我進行補充 面試官: Nacos如何處理網絡分區情況下的服務可用性問題? 我回答: 在討論 Nacos 如何處理網絡分區情況下的服務可用性問題時,我們需要深入理解 CAP 理論以及 Nacos 在這方面的設計選擇。Nacos 允許用戶根據具體的應用…

python解壓文件 zip tar.gz tar.xz

以下代碼為解壓zip包 tar包文件 zip_path:文件絕對路徑 output_folder:文件解壓后存放的文件夾路徑 def extract_file(zip_path, output_folder):# 支持解壓zip tar tar.gz tar.xz .tar.bz2# 確保輸出文件夾存在os.makedirs(output_folder, exist_okT…

網絡基礎(協議,地址,OSI模型、Socket編程......)

目錄 一、計算機網絡發展 二、協議 1.認識協議 2.OSI七層模型 3.TCP/IP 五層(或四層)模型 4.協議本質 三、網絡傳輸流程 1.MAC地址 2.協議棧 3.IP地址 IP地址 vs MAC地址 1. 核心區別 2. 具體通信過程類比 3. 關鍵總結 為什么需要兩者? 4.協議棧圖解…

生成式AI對話中提示詞策略:明確問題、明確目標和提供背景信息是最有效的策略

生成式AI對話中提示詞策略:明確問題、明確目標和提供背景信息是最有效的策略 最有效的提示詞策略包括明確問題、明確目標和提供背景信息。普適性有效提示詞策略可分為三類:明確需求與精確指引型、清晰解釋與邏輯排序型、拆解任務與多樣化表達型。[局限]數據來源于中國用戶,…