GO結構體

1. 結構體

Go語言可以通過自定義的方式形成新的類型,結構體就是這些類型中的一種復合類型,結構體是由零個或多個任意類型的值聚合成的實體,每個值都可以稱為結構體的成員。

結構體成員也可以稱為“字段”,這些字段有以下特性:

  • 字段擁有自己的類型和值;
  • 字段名必須唯一;
  • 字段的類型也可以是結構體,甚至是字段所在結構體的類型。

使用關鍵字 type 可以將各種基本類型定義為自定義類型,基本類型包括整型、字符串、布爾等。結構體是一種復合的基本類型,通過 type 定義為自定義類型后,使結構體更便于使用。

結構體的定義格式如下:

type 類型名 struct {字段1 字段1類型字段2 字段2類型…
}

  • 類型名:標識自定義結構體的名稱,在同一個包內不能重復。
  • struct{}:表示結構體類型,type 類型名 struct{}可以理解為將 struct{} 結構體定義為類型名的類型。
  • 字段1、字段2……:表示結構體字段名,結構體中的字段名必須唯一。
  • 字段1類型、字段2類型……:表示結構體各個字段的類型。

示例:

type Point struct {X intY int
}

顏色的紅、綠、藍 3 個分量可以使用 byte 類型:

type Color struct {R, G, B byte
}

結構體的定義只是一種內存布局的描述,只有當結構體實例化時,才會真正地分配內存

1.1 實例化

實例化就是根據結構體定義的格式創建一份與格式一致的內存區域,結構體實例與實例間的內存是完全獨立的。

基本的實例化形式:

結構體本身是一種類型,可以像整型、字符串等類型一樣,以 var 的方式聲明結構體即可完成實例化。

var ins T

1

T 為結構體類型,ins 為結構體的實例。

type Index struct {x inty int
}func main() {var myIndex Index//使用.來訪問結構體的成員變量,結構體成員變量的賦值方法與普通變量一致。myIndex.y = 10myIndex.x = 20fmt.Println(myIndex) //{20 10}}
//如果不賦值 結構體中的變量會使用零值初始化
type Point struct {X intY int
}
func main() {//可以使用var p = Point{X: 1,Y: 2,}var p = Point{1,2,}fmt.Printf("%v,x=%d,y=%d",p,p.X,p.Y )
}

創建指針類型的結構體:

Go語言中,還可以使用 new 關鍵字對類型(包括結構體、整型、浮點數、字符串等)進行實例化,結構體在實例化后會形成指針類型的結構體。

ins := new(T)

1

  • T 為類型,可以是結構體、整型、字符串等。
  • ins:T 類型被實例化后保存到 ins 變量中,ins 的類型為 *T,屬于指針。

下面的例子定義了一個玩家(Player)的結構,玩家擁有名字、生命值和魔法值:

	type Player struct {name  stringhp    intpower int}play := new(Player)play.power = 10play.name = "小米"play.hp = 150fmt.Println(*play)  //{小米 150 10}

取結構體的地址實例化:

在Go語言中,對結構體進行&取地址操作時,視為對該類型進行一次 new 的實例化操作,取地址格式如下:

ins := &T{}

其中:

  • T 表示結構體類型。
  • ins 為結構體的實例,類型為 *T,是指針類型。
type Commend struct {Name    stringVar     *intCommend string
}func newCommend(name string, Var *int, commend string) *Commend {return &Commend{name,Var,commend,}
}var version = 1func main() {m := newCommend("lct", &version, "test")fmt.Println(*m)  //{lct 0x5d4318 test}
}

1.2 匿名結構體

匿名結構體沒有類型名稱,無須通過 type 關鍵字定義就可以直接使用。

ins := struct {// 匿名結構體字段定義字段1 字段類型1字段2 字段類型2…
}{// 字段值初始化初始化字段1: 字段1的值,初始化字段2: 字段2的值,…
}

  • 字段1、字段2……:結構體定義的字段名。
  • 初始化字段1、初始化字段2……:結構體初始化時的字段名,可選擇性地對字段初始化。
  • 字段類型1、字段類型2……:結構體定義字段的類型。
  • 字段1的值、字段2的值……:結構體初始化字段的初始值。

// 打印消息類型, 傳入匿名結構體
func printMsg(msg *struct {id   intdata string
}) {fmt.Printf("type :%T,msg:%v", msg, msg)
}func main() {msg := &struct {id   intdata string}{21,"hello",}printMsg(msg) //type :*struct { id int; data string },msg:&{21 hello}
}

2. 方法

在Go語言中,結構體就像是類的一種簡化形式,那么類的方法在哪里呢?

在Go語言中有一個概念,它和方法有著同樣的名字,并且大體上意思相同,Go 方法是作用在接收器(receiver)上的一個函數,接收器是某種類型的變量,因此方法是一種特殊類型的函數。

接收器類型可以是(幾乎)任何類型,不僅僅是結構體類型,任何類型都可以有方法,甚至可以是函數類型,可以是 int、bool、string 或數組的別名類型,但是接收器不能是一個接口類型,因為接口是一個抽象定義,而方法卻是具體實現,如果這樣做了就會引發一個編譯錯誤invalid receiver type…

接收器也不能是一個指針類型,但是它可以是任何其他允許類型的指針。

一個類型加上它的方法等價于面向對象中的一個類

在Go語言中,類型的代碼和綁定在它上面的方法的代碼可以不放置在一起,它們可以存在不同的源文件中,唯一的要求是它們必須是同一個包的。

類型 T(或 T)上的所有方法的集合叫做類型 T(或 T)的方法集。

在面向對象的語言中,類擁有的方法一般被理解為類可以做的事情。在Go語言中“方法”的概念與其他語言一致,只是Go語言建立的“接收器”強調方法的作用對象是接收器,也就是類實例,而函數沒有作用對象。

為結構體添加方法:

需求:將物品放入背包

面向對象的寫法:

將背包做為一個對象,將物品放入背包的過程作為“方法”

type Bag struct {items []int
}func (b *Bag) Insert(item int) {b.items = append(b.items, item)
}func main() {var bag Bagbag.Insert(10)fmt.Println(bag.items) //[10]
}

(b*Bag) 表示接收器,即 Insert 作用的對象實例。每個方法只能有一個接收器

2.1 接收器

接收器的格式如下:

func (接收器變量 接收器類型) 方法名(參數列表) (返回參數) {函數體
}
  • 接收器變量:接收器中的參數變量名在命名時,官方建議使用接收器類型名的第一個小寫字母,而不是 self、this 之類的命名。例如,Socket 類型的接收器變量應該命名為 s,Connector 類型的接收器變量應該命名為 c 等。
  • 接收器類型:接收器類型和參數類似,可以是指針類型和非指針類型。
  • 方法名、參數列表、返回參數:格式與函數定義一致。

接收器根據接收器的類型可以分為指針接收器、非指針接收器,兩種接收器在使用時會產生不同的效果,根據效果的不同,兩種接收器會被用于不同性能和功能要求的代碼中。

指針類型的接收器:

指針類型的接收器由一個結構體的指針組成,更接近于面向對象中的 this 或者 self。

由于指針的特性,調用方法時,修改接收器指針的任意成員變量,在方法結束后,修改都是有效的。

示例:

使用結構體定義一個屬性(Property),為屬性添加 SetValue() 方法以封裝設置屬性的過程,通過屬性的 Value() 方法可以重新獲得屬性的數值,使用屬性時,通過 SetValue() 方法的調用,可以達成修改屬性值的效果:

type Property struct {val int
}// set val
func (p *Property) setVal(val int) {p.val = val
}//get valfunc (p *Property) getVal() int {return p.val
}func main() {p := new(Property)p.setVal(20)fmt.Println(p.getVal()) //20
}

非指針類型的接收器:

當方法作用于非指針接收器時,Go語言會在代碼運行時將接收器的值復制一份,在非指針接收器的方法中可以獲取接收器的成員值,但修改后無效。

點(Point)使用結構體描述時,為點添加 Add() 方法,這個方法不能修改 Point 的成員 X、Y 變量,而是在計算后返回新的 Point 對象,Point 屬于小內存對象,在函數返回值的復制過程中可以極大地提高代碼運行效率:

package main
import ("fmt"
)
// 定義點結構
type Point struct {X intY int
}
// 非指針接收器的加方法
func (p Point) Add(other Point) Point {// 成員值與參數相加后返回新的結構return Point{p.X + other.X, p.Y + other.Y}
}
func main() {// 初始化點p1 := Point{1, 1}p2 := Point{2, 2}// 與另外一個點相加result := p1.Add(p2)// 輸出結果fmt.Println(result)
}

在計算機中,小對象由于值復制時的速度較快,所以適合使用非指針接收器,大對象因為復制性能較低,適合使用指針接收器,在接收器和參數間傳遞時不進行復制,只是傳遞指針

4. 給任意類型添加方法

Go語言可以對任何類型添加方法,給一種類型添加方法就像給結構體添加方法一樣,因為結構體也是一種類型。

為基本類型添加方法:

在Go語言中,使用 type 關鍵字可以定義出新的自定義類型,之后就可以為自定義類型添加各種方法了。我們習慣于使用面向過程的方式判斷一個值是否為 0,例如:

if  v == 0 {// v等于0
}

如果將 v 當做整型對象,那么判斷 v 值就可以增加一個 IsZero() 方法,通過這個方法就可以判斷 v 值是否為 0,例如:

if  v.IsZero() {// v等于0
}

為基本類型添加方法的詳細實現流程如下:

package main
import ("fmt"
)
// 將int定義為MyInt類型
type MyInt int
// 為MyInt添加IsZero()方法
func (m MyInt) IsZero() bool {return m == 0
}
// 為MyInt添加Add()方法
func (m MyInt) Add(other int) int {return other + int(m)
}
func main() {var b MyIntfmt.Println(b.IsZero())b = 1fmt.Println(b.Add(2))
}

5. 匿名字段

結構體可以包含一個或多個匿名(或內嵌)字段,即這些字段沒有顯式的名字,只有字段的類型是必須的,此時類型也就是字段的名字。

匿名字段本身可以是一個結構體類型,即結構體可以包含內嵌結構體。

Go語言中的繼承是通過內嵌或組合來實現的,所以可以說,在Go語言中,相比較于繼承,組合更受青睞。


type User struct {id   intname string
}type Manager struct {User
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func main() {m := Manager{User{1, "lct"},}fmt.Printf("manger:%p\n", &m) //manger:0xc000094030fmt.Println(m.ToString())  //User:0xc000094030,&{id:1 name:lct}
}

有點類似于重寫

type User struct {id   intname string
}type Manager struct {Usertitle string
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func (m *Manager) ToString() string {return fmt.Sprintf("Manger:%p,%+v", m, m)
}func main() {m := Manager{User{1,"lct",}, "hahah"}fmt.Println(m.ToString()) //Manger:0xc00001a0f0,&{User:{id:1 name:lct} title:hahah}fmt.Println(m.User.ToString())  //User:0xc00001a0f0,&{id:1 name:lct}}

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

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

相關文章

JS清空數組方法

清空數組的方法有多種,以下是幾種常見的方式: 1.使用 array.length 屬性將數組的長度設為0,這樣會移除數組中的所有元素: var arr [1, 3, 5]; arr.length 0; console.log(arr); // [] 2. 使用 array.splice() 方法,…

STM32 | 零基礎 STM32 第一天

零基礎 STM32 第一天 一、認知STM32 1、STM32概念 STM32:意法半導體基于ARM公司的Cortex-M內核開發的32位的高性能、低功耗單片機。 ST:意法半導體 M:基于ARM公司的Cortex-M內核的高性能、低功耗單片機 32:32位單片機 2、STM32開發的產品 STM32開發的產品&a…

【論文筆記】Improving Language Understanding by Generative Pre-Training

Improving Language Understanding by Generative Pre-Training 文章目錄 Improving Language Understanding by Generative Pre-TrainingAbstract1 Introduction2 Related WorkSemi-supervised learning for NLPUnsupervised pre-trainingAuxiliary training objectives 3 Fra…

Java 網絡面試題解析

1. Http 協議的狀態碼有哪些?含義是什么?【重點】 200:OK,客戶端請求成功。 301:Moved Permanently(永久移除),請求的URL已移走。Response中應該包含一個Location URL,…

steam++加速問題:出現顯示443端口被 vmware-hostd(9860)占用的錯誤。

目錄 前言: 正文: 前言: 使用Steam對GitHub進行加速處理時,建議使用2.8.6版本。 下載地址如下:Release 2.8.6 BeyondDimension/SteamTools GitHub 下載時注意自己的系統位數 正文: 使用GitHub時會使…

NOC2023軟件創意編程(學而思賽道)python初中組初賽真題

軟件創意編程 一、參賽范圍 1.參賽組別:小學低年級組(1-3 年級)、小學高年級組(4-6 年級)、初中組。 2.參賽人數:1 人。 3.指導教師:1 人(可空缺)。 4.每人限參加 1 個賽項。 組別確定:以地方教育行政主管部門(教委、教育廳、教育局) 認定的選手所屬學段為準。 二、…

Mybatis-Plus+SpringBoot多數據源注解方式@DS

前言 最近接到一個新需求需要處理多數據源的問題 &#xff0c;今天就來和大家一起學習一下。 一、使用步驟 1.引入庫 代碼如下&#xff08;示例&#xff09;&#xff1a; <!--配置多數據源--><dependency><groupId>com.baomidou</groupId><artif…

藍橋杯Java B組歷年真題(2013年-2021年)

一、2013年真題 1、世紀末的星期 使用日期類判斷就行&#xff0c;這里使用LocalDate&#xff0c;也可以使用Calendar類 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:無需package // 2: 類名必須Main, 不可修改p…

常見問題和解決方案

OOM overview 發現監控告警 定位日志java.lang.OutOfMemoryError 避免參數配置代碼規范 example jvm性能調優實戰 -55RPC調用引發的OOM故障-阿里云開發者社區 (aliyun.com) 發現監控告警 定位日志java.lang.OutOfMemoryErrorA rpc BMAT打開堆快照文件分析histogram右擊看引…

CentOS7 Hive2.3.8安裝

CentOS7 Hive2.3.8 安裝 建議從頭用我的博客&#xff0c;如果用外教的文件到 一、9)步驟了&#xff0c;就用他的弄完&#xff0c;數據庫不一樣&#xff0c;在9步驟前還能繼續看我的 一、 安裝MySQL 0.0&#xff09;查詢mariadb,有就去0.1&#xff09;&#xff0c;沒有就不管…

python3裝飾器

裝飾器 它允許你修改函數或類的行為&#xff0c;而不更改其源代碼。實質上&#xff0c;裝飾器是接受另一個函數作為參數并返回一個包裝原始函數的新函數。這樣&#xff0c;你可以在不修改原始函數的情況下&#xff0c;添加一些額外的功能或邏輯。 def time_cost(func):"…

排隊接水問題

時間限制&#xff1a;1秒 內存限制&#xff1a;128M 題目描述 有n個人在一個水龍頭前排隊接水&#xff0c;假如每個人接水的時間為Ti&#xff0c;請編程找出這n個人排隊的一種順序&#xff08;若有多種順序則編號小的在前&#xff09;&#xff0c; 使得n個人的平均時間…

ARCGIS進行視域分析及地形圖制作

問題說明 開發商要在本區域建造觀景亭,希望在觀景亭上能看到優美的景色。根據提供的數據,完成以下要求。 一、 數據說明(見“題目3”文件夾) 1. DEM.tif:研究區域的數據高程模型數據。 2. 觀察點.shp:需要建造觀景亭的位置。

美團分布式 ID 框架 Leaf 介紹和使用

一、Leaf 在當今日益數字化的世界里&#xff0c;軟件系統的開發已經成為了幾乎所有行業的核心。然而&#xff0c;隨著應用程序的規模不斷擴大&#xff0c;以及對性能和可擴展性的需求不斷增加&#xff0c;傳統的軟件架構和設計模式也在不斷地面臨挑戰。其中一個主要挑戰就是如…

學生云服務器_學生云主機_學生云數據庫_云+校園特惠套餐

2024年騰訊云學生服務器優惠活動「云校園」&#xff0c;學生服務器優惠價格&#xff1a;輕量應用服務器2核2G學生價30元3個月、58元6個月、112元一年&#xff0c;輕量應用服務器4核8G配置191.1元3個月、352.8元6個月、646.8元一年&#xff0c;CVM云服務器2核4G配置842.4元一年&…

自注意力機制(Self-Attention)

注意&#xff1a;本文引用自專業人工智能社區Venus AI 更多AI知識請參考原站&#xff08;【http://www.aideeplearning.cn】&#xff09; Transformer模型中最關鍵部分就是自注意力&#xff08;Self-Attention&#xff09;機制&#xff0c;正如 Transformer 的論文的標題是“…

【Vue3】函數式編程(h 函數)

h 函數的原理就是 createVNode。可以使用 h 函數封裝一些小組件。 <template><table border><tr><th>name</th><th>age</th><th>操作</th></tr><tr v-for"item in list" :key"item.age"&…

shell封裝

shift 命令用于對參數的移動(左移)&#xff0c;通常用于在不知道傳入參數個數的情況下依次遍歷每個參數然后進行相應處理&#xff08;常見于Linux中各種程序的啟動腳本&#xff09; shift(shift 1) 命令每執行一次&#xff0c;變量的個數($#)減一&#xff0c;移動2位可以 執行…

數據結構實現-線性表

順序存儲 #include<iostream> using namespace std; #define MaxSize 50 //靜態順序表 template<typename ElemType> struct sqList{ElemType data[MaxSize];//元素int length;//長度 }; //動態順序表 #ifdef DEBUG //關閉啟用 #define InitSize 100 template<…

嵌入式LINUX移植、配置ssh

編譯 https://quantum6.blog.csdn.net/article/details/136299665 編譯時指定prefix&#xff0c;產生的文件會自帶這個目錄。所以直接忽略。 ./configure# 不指定編譯路徑&#xff0c;手動復制。 復制 編譯后的整個目錄打包&#xff0c;復制到開發板。寫個腳本&#xff0c…