保證型別安全:使用Go的Type Assertions避免型別錯誤

更新於 發佈於 閱讀時間約 9 分鐘


raw-image

👨‍💻簡介

在Go中,假如我要判斷一個資料類型是甚麼,該怎麼做呢? Golang有一個功能叫做Type Assertions(類型斷言),它的作用就是能夠在運行時檢查我的資料類型,讓我在傳遞類型時能確保資料類型是正確的。

Type Assertions 的基本概念

在Go中,Type Assertions的主要目的是在運行時將 interface 型別的值轉換為特定的實際型別。interface 是一種特殊的類型,它可以保存任何值的實例,但在運行時,我們可能需要確定該值的實際類型以執行相應的操作,以確保我們能夠安全地操作資料,這就是Type Assertions的作用。

Type Assertions的基本語法如下:

value, ok := someInterface.(T)

這個表達式意思為將someInterface轉換為類型T。如果成功,它將value設置為轉換後的值,並將ok設置為true。如果轉換失敗,則value將是零值,而ok將是false

Type Assertions的用途

Type Assertions 的主要用途包括:

  1. 資料型別的轉換

當我們處理interface型別的資料時,可能需要將其轉換為具體的型別,以便進行特定操作。

func process(someInterface interface{}) {
if str, ok := someInterface.(string); ok {
// 將interfacce轉換為string類型並進行操作
fmt.Printf("Length of string: %d\n", len(str))
} else {
fmt.Println("Not a string")
}
}

2. 確保型別的正確性

使用 Type Assertions,我們可以在執行特定操作之前,確保資料的型別是我們期望的。這有助於防止因型別錯誤而引發的執行時錯誤。

if val, ok := someInterface.(int); ok {
// someInterface 是一個int類型
fmt.Printf("Value is an int: %d\n", val)
} else {
// someInterface 不是一個int類型
fmt.Println("Value is not an int")
}

3. 在接口值中存儲額外信息

Type Assertions還可用於在interface中儲存額外的資料,這些資料只在特定類型時才可用。 以下程式碼使用Type Assertions 和 switch 來處理不同的struct

type Circle struct {
Radius float64
}

type Square struct {
SideLength float64
}
func printArea(shape interface{}) {
switch val := shape.(type) {
case Circle:
area := 3.14159265359 * val.Radius * val.Radius
fmt.Printf("Area of the circle: %f\n", area)
case Square:
area := val.SideLength * val.SideLength
fmt.Printf("Area of the square: %f\n", area)
default:
fmt.Println("Unknown shape")
}
}

Type Assertions 的實際應用

以下簡單介紹實際應用情況:

  1. JSON 解碼:當解碼 JSON 資料時,通常會解碼為 map[string]interface{} 或 []interface{},這些 interface 型別可以讓我們能夠動態處理資料,但有時我們需要將它們轉換為具體的 struct,以便更方便地使用。
package main

import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
jsonData := `{"Name": "Alice", "Age": 30}`
var data interface{}
err := json.Unmarshal([]byte(jsonData), &data)
if err != nil {
fmt.Println("JSON 解碼失敗:", err)
return
}
// 使用 Type Assertions 將介面型別轉換為結構體型別
if person, ok := data.(map[string]interface{}); ok {
name := person["Name"].(string)
age := int(person["Age"].(float64))
fmt.Printf("Name: %s, Age: %d\n", name, age)
} else {
fmt.Println("資料型別不是預期的 map[string]interface{}")
}
}

可以看到,我們首先解碼了一個 JSON 字串,並儲存在一個 interface 型別的變數 data 中。然後,我們使用 Type Assertions 將 data 斷言為 map[string]interface{} 型別,讓我們能夠訪問其中的字段。

2. 反射(Reflection): reflect 通常用於檢查和操作變數、struct 和 interface 型別的訊息。 在某些情況下,Type Assertions 在reflect 過程中經常派上用場,用於確認 interface 型別的實際內容。

package main

import (
"fmt"
"reflect"
)
func main() {
var x interface{} = 42
// 使用 Type Assertions 檢查實際型別
if val, ok := x.(int); ok {
fmt.Printf("x 是一個整數,值為:%d\n", val)
} else {
fmt.Println("x 不是一個整數")
}
// 使用 reflect 獲取型別信息
t := reflect.TypeOf(x)
fmt.Printf("x 的實際型別是:%s\n", t)
}

在這個範例中,我們首先使用 Type Assertions 檢查 x 的實際型別,然後使用 reflect 獲取型別信息。Type Assertions 確保了我們在確定型別後才能安全地訪問 val 變數。

Type Assertions 使用時的注意事項

在使用 Type Assertions 時,有些注意事項有助於確保程式碼如預期運作,並減少潛在的執行時錯誤。

  1. 始終檢查 ok 值:當進行 Type Assertions 時,無論如何都應該始終檢查 ok 值。這是確保轉換成功的關鍵。如果 ok 的值為 false,代表斷言失敗,你應該採取適當的錯誤處理措施,而不是假設轉換已成功。
  2. 使用 switch 語句:當處理多種可能的資料型別時,最好使用 switch 語句來進行 Type Assertions。這樣做的好處是,它使你的程式碼更具可讀性,並且更容易擴展。每個 case 子句可以處理一種特定的型別,讓程式邏輯清晰明瞭。
  3. 避免過多的 Type Assertions:過多的 Type Assertions 可能是程式設計上的警號,可能表示你的設計存在問題。儘量避免在程式碼中過多使用 Type Assertions,而是考慮使用 interface 和多態性來實現更優雅的設計。正確的 interface 設計可以減少對 Type Assertions 的需求,使程式碼更加簡潔且易於維護。

小結

Go 語言的 Type Assertions 讓我們能夠更好地處理不同資料型別的情況,同時保持程式的可讀性和安全性。無論是在處理 JSON 數據、實現 reflect 功能,Type Assertions 都是一個不可或缺的功能,有助於 Go 語言的應用程式開發更加靈活和強大。

📚Reference

avatar-img
17會員
83內容數
golang
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Alan的開發者天地 的其他內容
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
👨‍💻簡介 在程式開發的世界中,我們經常需要處理各式各樣的資料,可能是一個人的個人資訊,也可能是一個商品的詳細訊息。當我們面對這麼多的資料時,如何將它們有系統地整理起來,讓我們能夠輕鬆地找到所需,便成了一個重要的課題。這時,結構體的概念就像是一道曙光,為我們提供了一個非常有力的工具。 結
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
👨‍💻簡介 在程式開發的世界中,我們經常需要處理各式各樣的資料,可能是一個人的個人資訊,也可能是一個商品的詳細訊息。當我們面對這麼多的資料時,如何將它們有系統地整理起來,讓我們能夠輕鬆地找到所需,便成了一個重要的課題。這時,結構體的概念就像是一道曙光,為我們提供了一個非常有力的工具。 結
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
今天要來介紹的是Python中資料型別的函數, 這幾天學習的素材是Youtube上“程式柴大大的Python 6 小時初學者課程”,一步一步帶著大家操作並解,學習中也別忘了要多多練習,練習的部分我是把我學到的東西請Chatgpt幫我出類似的題型並讓我練習。 以下我先寫出一個簡單的code,再加以
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
Thumbnail
內容涵蓋資料型別、型別轉換、自訂型別、元組型別、集合型別和字典型別等主題。文章首先詳述內建型別如bool、byte、char等的定義和使用,接著討論型別轉換,包括隱含轉換和明確轉換。之後文章介紹自訂型別的建立,以及元組、集合、陣列和字典型別的操作與例子。
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
本文帶你深入探索 TypeScript 中的 satisfies 特性,能幫助你實現精確的型別推導與型別檢查。透過實際案例,展示如何使用 satisfies 提升代碼的型別安全與程式碼的整潔,是每位 TypeScript 開發者不可或缺的知識。
Thumbnail
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
Thumbnail
在程式開發中,協作合作專案時,利用type hint,可以快速知道函式輸入及輸出的資料型別,在後續的維護時也會更加方便及可讀。 Type hints 是Python 3.5 版本引入的功能,它允許在函數宣告中指定參數和傳回值的類型。Type hints 是一種可選的註解形式,不會影響程式碼的運行,
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
前幾篇文章討論了類型系統的合理性,而這會影響我們對於變數與函式是什麼的理解。其中泛型是當中很重要的一個元素,很多討論都是基於泛型的使用。泛型會大大地增加類型系統的複雜度,因此有些語言選擇不提供泛型(go),但缺少泛型又會使簡單的容器都無法用類型精確描述。泛型的強大必須結合有紀律的類型系統才能顯現,但
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
今天要來介紹的是Python中資料型別的函數, 這幾天學習的素材是Youtube上“程式柴大大的Python 6 小時初學者課程”,一步一步帶著大家操作並解,學習中也別忘了要多多練習,練習的部分我是把我學到的東西請Chatgpt幫我出類似的題型並讓我練習。 以下我先寫出一個簡單的code,再加以
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
Thumbnail
內容涵蓋資料型別、型別轉換、自訂型別、元組型別、集合型別和字典型別等主題。文章首先詳述內建型別如bool、byte、char等的定義和使用,接著討論型別轉換,包括隱含轉換和明確轉換。之後文章介紹自訂型別的建立,以及元組、集合、陣列和字典型別的操作與例子。
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
本文帶你深入探索 TypeScript 中的 satisfies 特性,能幫助你實現精確的型別推導與型別檢查。透過實際案例,展示如何使用 satisfies 提升代碼的型別安全與程式碼的整潔,是每位 TypeScript 開發者不可或缺的知識。
Thumbnail
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
Thumbnail
在程式開發中,協作合作專案時,利用type hint,可以快速知道函式輸入及輸出的資料型別,在後續的維護時也會更加方便及可讀。 Type hints 是Python 3.5 版本引入的功能,它允許在函數宣告中指定參數和傳回值的類型。Type hints 是一種可選的註解形式,不會影響程式碼的運行,
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
前幾篇文章討論了類型系統的合理性,而這會影響我們對於變數與函式是什麼的理解。其中泛型是當中很重要的一個元素,很多討論都是基於泛型的使用。泛型會大大地增加類型系統的複雜度,因此有些語言選擇不提供泛型(go),但缺少泛型又會使簡單的容器都無法用類型精確描述。泛型的強大必須結合有紀律的類型系統才能顯現,但