Go語言中的結構體:靈活性與可擴展性的重要角色

来源:https://www.cnblogs.com/chenjiazhan/archive/2023/06/14/17481422.html
-Advertisement-
Play Games

函數是帶名字的代碼塊,用於完成具體的工作,無需反覆編寫完成該工作的代碼。之前我們接觸過print函數,數據類型轉換中的int函數、str函數,還有列表中的append函數、pop函數、remove函數,以及字典中的keys函數、values函數等等,其實在正式學習函數之前,我們已經接觸了函數,只不過 ...


1. 引言

結構體是Go語言中重要且靈活的概念之一。結構體的使用使得我們可以定義自己的數據類型,並將不同類型的欄位組合在一起,實現更靈活的數據結構。本文旨在深入介紹Go語言中的結構體,揭示其重要性和靈活性,並向讀者展示結構體支持的眾多特性,展示其強大之處。

2. 什麼是結構體?

在Go語言中,結構體是一種自定義的數據類型,用於將不同類型的欄位組合在一起形成一個新的數據結構。結構體定義了一組欄位,每個欄位可以有不同的類型,這些欄位一起構成了結構體的實例。通過結構體,我們可以將相關的數據進行組織和管理,從而更方便地進行操作和傳遞。

結構體的定義使用關鍵字typestruct。以下是結構體的定義語法:

type 結構體名稱 struct {
    欄位1 類型1
    欄位2 類型2
    // 更多欄位...
}

在上述語法中,結構體名稱是我們為結構體類型起的名稱,可以根據實際情況進行命名。而結構體的欄位部分則列出了結構體包含的所有欄位,每個欄位都有一個欄位名和對應的欄位類型。下麵我們給出一個結構體定義的示例:

type User struct {
    Name string
    Age  int
    Address string
}

述結構體定義了一個名為User的結構體類型,它包含了兩個欄位:NameAge,它們的類型分別為字元串、整數。到此為止,我們完成了對結構體的基本介紹,能夠基於此創建出一種新的數據類型。

但是結構體的定義只是創建了一種新的數據類型,使用結構體需要創建其實例,Go語言中提供了幾種實例化方式,下麵我們將對其進行詳細講述。

首先,可以使用結構體字面量直接初始化結構體變數,按照欄位順序給出對應的值。示例如下:

person := Person{"Alice", 25, "廣東深圳"}

其次可以使用指定欄位名的方式給出欄位的初始化值,這個時候可以忽略某些欄位。示例如下:

person := Person{Name: "Alice", Age: 25}

也可以使用new關鍵字創建一個指向結構體的指針,並返回該指針。示例如下:

personPtr := new(Person)
personPtr.Name = "Alice"
personPtr.Age = 25

亦或者使用var關鍵字聲明結構體變數,然後分別給欄位賦值。示例如下:

var person Person
person.Name = "Alice"
person.Age = 25

以上是常見的結構體實例化和初始化方法,根據實際需要選擇合適的方式。無論使用哪種方式,都可以創建並初始化結構體的實例,以便後續使用和操作結構體的欄位。

到此為止,我們介紹了什麼是結構體,其實結構體可以認為是一組不同類型欄位的組合,將其用來表示一個新的概念。其次我們也介紹了幾種實例化自定義結構體的方式,基於此我們對結構體有一個大概的瞭解。

3. 結構體支持哪些特性呢?

上面我們對結構體有了基本的瞭解,結構體可以組合一組不同類型的欄位,將其用來表示一個新的概念。但是結構體並不止步於此,其也支持定義方法,數據封裝等。通過這些特性,結構體在Go語言中具備了靈活性、可擴展性和可讀性,並且在面向對象編程、數據建模和代碼復用等方面發揮著重要作用。

3.1 結構體支持定義方法

結構體在Go語言中支持定義方法,方法是與結構體關聯的函數。這種特性使得我們可以將特定的行為和功能與結構體關聯起來,通過方法來操作結構體的數據。

下麵是一個示例,演示了結構體支持定義方法的特性:

package main

import "fmt"

// 定義結構體
type Person struct {
    Name string
    Age  int
}

// 定義方法:列印個人信息
func (p Person) PrintInfo() {
    fmt.Printf("Name: %s\n", p.Name)
    fmt.Printf("Age: %d\n", p.Age)
}

// 定義方法:修改年齡
func (p Person) UpdateAge(newAge int) {
    p.Age = newAge
}

func main() {
    // 創建一個 Person 結構體實例
    person := Person{Name: "John", Age: 30}
    // 調用結構體的方法:列印個人信息
    person.PrintInfo() // Output: Name: John   Age: 30
    // 調用結構體的方法:修改年齡
    person.UpdateAge(35)
    // 再次調用方法,列印修改後的個人信息
    person.PrintInfo() // Output: Name: John   Age: 35
}

在上述代碼中,我們定義了一個 Person 結構體,它包含了 NameAge 兩個欄位。然後,我們為結構體定義了兩個方法:PrintInfo()UpdateAge()

main() 函數中,我們創建了一個 Person 結構體實例 person,並通過該實例調用了兩個方法:PrintInfo()UpdateAge()。首先,我們調用 PrintInfo() 方法,列印出初始的個人信息。然後,我們調用 UpdateAge() 方法,將年齡修改為 35。最後,我們再次調用 PrintInfo() 方法,列印修改後的個人信息。

通過結構體定義方法,我們可以將與結構體相關的數據和操作封裝在一起,提高了代碼的可讀性和可維護性。方法能夠直接訪問結構體的欄位,並對其進行操作,使得代碼更加簡潔和清晰。

3.2 結構體支持數據可見性的設置

結構體在Go語言中支持數據可見性的特性。其通過首字母大小寫可以限制結構體欄位和方法的可見性,從而實現信息的隱藏和封裝。

在結構體中,方法名或者欄位名,其首字母大寫,代表著對外是可見和可修改的;首字母小寫,則代表著對外為不可見的。如果想要讀取或者修改,只能通過對外暴露的介面來進行,通過這種方式,可以隱藏結構體的內部實現細節,同時確保對結構體數據的訪問和操作通過封裝的公開方法進行,提供了更好的安全性和封裝性。下麵給出一個代碼的示例:

package main

import "fmt"

// 定義結構體
type Person struct {
    name string // 私有欄位
}

// 定義公開方法:設置姓名
func (p *Person) SetName(name string) {
    p.name = name
}

// 定義公開方法:獲取姓名
func (p *Person) GetName() string {
    return p.name
}

func main() {
    // 創建一個 Person 結構體實例
    person := Person{}
    // 這裡將無法通過編譯
    // person.name = "hello eva"
    // 通過公開方法設置姓名和年齡
    person.SetName("John")
    // 通過公開方法獲取姓名和年齡並列印
    fmt.Println("Name:", person.GetName()) // Output: Name: John

}

上述代碼中,我們定義了一個 Person 結構體,它包含了 name 這個私有欄位。然後,我們為結構體定義了兩個公開方法GetName()SetName(),可以分別進行設置和讀取私有欄位name欄位的值。

如果直接通過結構體實例person去讀取name欄位,此時將無法通過編譯。通過這種方式,確保對結構體數據的訪問和操作通過封裝的公開方法進行,提供了更好的安全性和封裝性。

3.3 結構體能夠實現介面

介面定義了一組方法的契約,描述了這些方法的行為和簽名。

在Go語言中,介面是一種類型,由一組方法簽名組成。一個結構體可以實現該介面中的所有方法,此時可以認為其實現了該介面,從而可以以相同的方式被使用。這種特性提供了多態性,允許我們編寫通用的代碼,適用於多種類型的結構體。以下是一個示例,演示了結構體如何實現一個介面:

package main

import "fmt"

// 定義介面
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 定義矩形結構體
type Rectangle struct {
    Width  float64
    Height float64
}

// 實現介面方法:計算矩形的面積
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// 實現介面方法:計算矩形的周長
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func main() {
    // 創建一個矩形結構體實例
    rectangle := Rectangle{Width: 5, Height: 3}

    // 將矩形實例賦值給介面變數
    var shape Shape
    shape = rectangle

    // 通過介面調用方法,計算面積和周長
    area := shape.Area()
    perimeter := shape.Perimeter()

    fmt.Println("Area:", area)           // Output: Area: 15
    fmt.Println("Perimeter:", perimeter) // Output: Perimeter: 16
}

在上述代碼中,我們定義了一個介面 Shape,它包含了 Area()Perimeter() 兩個方法的簽名。然後,我們定義了一個矩形結構體 Rectangle,併為該結構體實現了介面 Shape 中定義的方法。

main() 函數中,我們創建了一個矩形結構體實例 rectangle。然後,我們將該矩形實例賦值給介面類型的變數 shape,因為矩形結構體實現了 Shape 介面,所以可以賦值給介面變數。

接著,我們通過介面變數 shape 調用了 Area()Perimeter() 方法,實際上是調用了矩形結構體上的對應方法。通過介面的調用方式,我們可以使用統一的方式對不同的結構體類型進行操作,無需關心具體的類型。

這種結構體實現介面的特性提供了多態性的支持,使得我們可以編寫通用的代碼,適用於多種類型的結構體。它使得代碼更加靈活、可擴展,並且能夠更好地應對需求的變化。

3.4 結構體支持組合

結構體支持組合的特性,通過將其他結構體作為欄位嵌入,實現了代碼的復用和組合。這樣做可以使外部結構體直接訪問嵌入的結構體的欄位和方法,從而復用內部結構體的功能。

具體而言,通過在外部結構體中嵌入其他結構體作為匿名欄位,我們可以直接訪問內部結構體的欄位和方法,而無需顯式進行委托或包裝。下麵是一個示例,演示了結構體支持組合的特性:

package main

import "fmt"

// 定義基礎結構體
type Person struct {
        Name string
        Age  int
}

// 定義擴展結構體,嵌入了基礎結構體
type Employee struct {
        Person     // 匿名欄位,嵌入 Person 結構體
        EmployeeID int
}

func main() {
        // 創建一個 Employee 結構體實例
        employee := Employee{
                Person: Person{
                        Name: "John",
                        Age:  30,
                },
                EmployeeID: 12345,
        }

        // 訪問內部結構體的欄位和方法
        fmt.Println("Name:", employee.Name) // Output: Name: John
        fmt.Println("Age:", employee.Age)   // Output: Age: 30
}

在上述代碼中,我們定義了兩個結構體:PersonEmployeeEmployee 結構體通過嵌入 Person 結構體作為匿名欄位實現了組合。

通過組合,Employee 結構體可以直接訪問嵌入欄位 Person 的欄位 NameAge。在 main() 函數中,我們創建了一個 Employee 結構體實例 employee,並可以直接訪問其內部結構體 Person 的欄位。

通過組合,我們可以復用其他結構體中的欄位和方法,避免重覆編寫相同的代碼。這樣可以提高代碼的復用性和可維護性。其次,組合也提供了一種靈活的方式來擴展結構體的功能,我們可以將介面類型作為欄位嵌入進去,在不同的場景下可以使用不同的實現,使得整個設計更加靈活。

結構體支持組合的特性,極大得增強了Go語言的表達力,使得我們可以更好地組織和管理代碼,實現更靈活和可擴展的程式設計。

3.5 結構體標簽支持

結構體支持設置標簽是 Go 語言提供的一個特性。標簽是以字元串形式附加在結構體欄位上的元數據,用於提供額外的信息和配置。這個特性是由 Go 語言的編譯器和相關庫支持的,同時遵循了 Go 語言定義的標準格式。

結構體標簽的格式為key:"value",可以包含一個或多個鍵值對,多個鍵值對之間使用空格分隔。標簽位於欄位聲明的反引號中,例如:

type Person struct {
        Name string `json:"name" db:"full_name"`
        Age  int    `json:"age" db:"age"`
}

Go語言中,結構體標簽已經在許多場景下起到了非常重要的作用。其中包含結構體的序列化和反序列化,資料庫映射,表單驗證等。下麵我們簡單通過一個序列化的場景來簡單說明,更詳細的內容後續再講述。

type Person struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
}

func main() {
        p := Person{Name: "John Doe", Age: 30}
        data, _ := json.Marshal(p)
        fmt.Println(string(data)) // Output: {"name":"John Doe","age":30}
}

在上述示例中,通過設置欄位的 json 標簽,我們可以指定 JSON 序列化時的欄位名稱,使得生成的 JSON 字元串符合預期的格式。

這裡,結構體標簽的設置可以提供更多的元數據和配置信息,使得代碼更具可讀性、可維護性和靈活性。同時,標簽的解析和應用是在運行時進行的,使得我們可以在編寫代碼時靈活配置和調整結構體欄位的行為,而無需修改代碼本身,這提供了更大的靈活性和便利性。

3.6 特性總結

在Go語言中,結構體是一種強大而靈活的數據類型,其支持方法的定義,也能夠實現介面,組合以及對可見性的設置。

這些特性的結合使得Go語言中的結構體非常強大和靈活。用戶可以使用結構體定義自己的數據類型,併為其定義方法和行為。同時,結構體可以與介面一起使用,實現多態性和代碼復用。結構體的組合和可見性設置提供了更高級別的抽象和封裝能力,使代碼更具可擴展性和可維護性。

同時結構體也定義了一套標簽規則,能夠使用標簽為欄位添加元數據,這增強了代碼的功能和表現力,在註釋、序列化、校驗和映射等方面,提高了代碼的可擴展性和可復用性。

4. 總結

在這篇文章中,我們首先從結構體的定義入手,明確瞭如何定義結構體,並介紹了結構體的四種實例化方式。通過這些基礎知識,我們對結構體有了一個基本的瞭解。

接下來,我們詳細討論了結構體支持的幾個重要特性。我們介紹了結構體支持定義方法的能力,使得我們可以為結構體添加自定義的行為。我們還瞭解瞭如何對結構體支持對數據可見性的設置,通過訪問控制來保護數據的安全性。我們還介紹了結構體能夠對介面進行實現,使得結構體可以滿足介面的要求,實現更靈活的代碼組織和抽象。最後我們還講述了結構體支持組合的特性,允許我們將多個結構體組合成一個更大的結構體,實現代碼的復用和組合性。

綜上所述,本文全面介紹了結構體的定義和實例化方式,並詳細講解了結構體支持的各種特性。基於以上內容,完成了對Go語言結構體的介紹,希望對你有所幫助。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 向量資料庫和 Embedding 是當前 AI 領域的熱門話題。 Pinecone 是一家向量資料庫公司,剛剛以約 10 億美元的估值籌集了 1 億美元。 Shopify、Brex、Hubspot 等公司都在他們的 AI 應用程式中使用向量資料庫和 Embedding。那麼,它們究竟是什... ...
  • 原文: [Kotlin 集合對象的單條件和多條件排序 - Stars-One的雜貨小窩](https://stars-one.site/2023/06/14/kotlin-list-sort) 本文不是太難的東西,因為`sortedWith`之前沒怎麼用過,所以就記錄下 平常開發經常使用到List, ...
  • 618是每年重要的電商大促活動,熱度高流量大,是電商App吸引新用戶,提高用戶轉化率(購買率)的最好時機。對電商App運營來說,消息推送是不可忽略的流量來源之一,適當的消息推送可以召回用戶,提高用戶復購率。如何利用消息推送功能在618電商節幫助App獲取流量並提高轉化率是運營需要關註的問題。 在回答 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 使用ElementPlus的Table啥都好,就是沒有可編輯表格!!!😭 既然UI庫不支持,那我們實現一個可編輯表格是很難的事麽?😒難麽?😢不難麽?... 個人覺得如果是業務固定的可編輯表格,使用ElementPlus實現都不難。但 ...
  • 起因 為了降低併發時的API請求量, 這兩天寫了個LRU Cache. 其中用到了Set做AllowList, 來判斷API是否應該被緩存. 在MDN查API時, 發現Set被歸類在Keyed Collection中. 一直以來, 下意識覺得Set只是value唯一的Array. 應該屬於Index ...
  • 本文將對測試驅動開發(TDD)進行探討,主要內容有:TDD基本理解、TDD常見誤區、TDD技術選型,以及案例實戰。希望通過本文,讀者能夠理解掌握TDD並將其應用於實際開發中。 ...
  • 某日二師兄參加XXX科技公司的C++工程師開發崗位第14面: > 面試官:在C++中,有哪些可執行體? > > 二師兄:可執行體? > > 面試官:也就是可調用對象。 > > 二師兄:讓我想一想。函數、函數指針、類的靜態方法、類的成員方法、仿函數、lambda表達式。 > > 面試官:能說一說他們之 ...
  • Set 介面是 Collection 介面的一個子介面。Set 介面的實現類不會包含重覆的元素,並且最多只能有一個 null 元素。當嘗試添加重覆元素時,添加操作將被忽略。Set 介面取出元素的順序和添加元素的順序不一致(但是每次取出的順序是固定的),即無法通過索引訪問 Set 中的元素。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...