Go-知識struct

Go-知識struct

  • 1. struct 的定義
    • 1.1 定義字段
    • 1.2 定義方法
  • 2. struct的復用
  • 3. 方法受體
  • 4. 字段標簽
    • 4.1 Tag是Struct的一部分
    • 4.2 Tag 的約定
    • 4.3 Tag 的獲取

githupio地址:https://a18792721831.github.io/

1. struct 的定義

Go 語言的struct與Java中的class類似,可以定義字段和方法,但是不能繼承。

1.1 定義字段

struct定義字段非常簡單,只需要將字段寫在struct的結構中,比如:

type tes struct {a intName string
}

需要注意的是,在Go里面,訪問權限是通過name的大小寫指定的,小寫表示包內可見,如果是大寫則表示包外可見。
所以上面的struct如果用Java翻譯:

class tes {private int a;public String Name;
} 

同樣的,如果創建的struct想讓包外可見,那么必須是大寫開頭。

type Tes struct{id intName string
}

1.2 定義方法

在Go里面一般不會區分函數和方法,或者更好理解的話,可以認為方法是受限的函數,限制了函數調用者,那么就是方法。
定義方法:

func (a tes) test() {fmt.Println(a.id)
}

同樣的,上述方法包內可見。

func (a tes) Test() {fmt.Println(a.Name)
}

上述方法雖然包外可見,但是沒有意義,因為tes是包內可見,如果沒有對外提供函數,那么是沒有意義的。
如果想保證安全,可以使用包內可見的struct配合包內字段加包外方法,另外額外提供包外可見的struct獲取函數,實現類似于Java的可見性控制。

package testype person struct {id   intname stringage  int
}func (this *person) GetId() int {return this.id
}func (this *person) GetName() string {return this.name
}func (this *person) GetAge() int {return this.age
}func (this *person) SetId(id int) {this.id = id
}func (this *person) SetName(name string) {this.name = name
}func (this *person) SetAge(age int) {this.age = age
}func NewPerson() *person {return &person{}
}func NewPersonWithId(id int) *person {return &person{id: id}
}func NewPersonWithName(name string) *person {return &person{name: name}
}

因為Go不支持函數重載,所以需要用不同的函數名字區分。
上述代碼實際上就是一個基本的JavaBean的實現。
但是實際使用上,基本上對外可見的字段都是直接用.來訪問和賦值的。
在使用上,struct是否對外可見,則和編碼風格相關,業務系統一般不會考慮封閉性,基本上struct都是可見的;而第三方包等為了保證安全性,則會將部分struct設置為包內可見,在結合interface來保證擴展性。

2. struct的復用

在其他編程語言中,使用繼承或組合實現代碼的復用。
而Go語言中沒有繼承,只能使用組合實現復用。
比較特別的是,在Go語言中,組合復用的struct可以認為拷貝了被組合的struct的字段到需要的struct中。

type Man struct {personsex string
}func (this *Man) ToString() string {return fmt.Sprintf("id=%d, name=%s, age=%d, sex=%s\n", this.person.id, this.person.name, this.person.age, this.sex)
}func (this *Man) GetToString() string {return fmt.Sprintf("id=%d, name=%s, age=%d, sex=%s\n", this.id, this.name, this.age, this.sex)
}

在struct中組合其他struct,相當于是創建了一個同名的隱式字段,在使用的時候,可以指明隱式字段,也可以不指明隱式字段。
想一想,在Java中,如果當前class和父class中有同名的字段,那么在使用父類中的字段時,需要使用super指明使用的是父類中的字段。
同理的,當struct中有一個id,那么在使用的時候,可以使用隱式字段指明:

type Man struct {id intpersonsex string
}func (this *Man) GetSuperId() int {return this.person.id
}func (this *Man) GetManId() int {return this.id
}

隱式字段如果顯示的定義了,那么就無法像使用自己的字段一樣使用內嵌字段了:

type Woman struct {person personsex    string
}func (this *Woman) ToString() string {return fmt.Sprintf("id=%d, name=%s, age=%d, sex=%s\n", this.person.id, this.person.name, this.person.age, this.sex)
}func (this *Woman) GetString() string {return fmt.Sprintf("id=%d, name=%s, age=%d, sex=%s\n", this.id)
}

如果還像使用自己的字段一樣使用內嵌字段,就會找不到
在這里插入圖片描述

3. 方法受體

方法本質上還是函數,只是限制了函數的調用者。
那么你有沒有好奇,為什么上面的例子中,方法的調用者都是指針類型而不是struct類型,這有什么區別?

type person struct {id   intname stringage  int
}func (this *person) SetIdPtr(id int) {this.id = id
}func (this person) SetId(id int) {this.id = id
}func (this *person) GetIdPtr() int {return this.id
}func (this person) GetId() int {return this.id
}func TestPerson(t *testing.T) {p := person{id:   1,name: "zhangsan",age:  10,}fmt.Printf("%+v\n", p)p.SetId(2)fmt.Printf("%+v\n", p)p.SetIdPtr(3)fmt.Printf("%+v\n", p)p.id = 4fmt.Printf("%+v\n", p.GetIdPtr())p.id = 5fmt.Printf("%+v\n", p.GetId())
}

在這里插入圖片描述

沒錯,區別在于是否會影響原數據。
函數調用過程中,會將函數壓入調用棧,在入棧過程中,會對函數參數進行拷貝。
在Java中,如果是基本類型參數,那么拷貝值,如果是復雜類型參數,那么拷貝指針。
在Go語言中,可以由程序員指定,如果方法調用者是指針,那么表示方法可以修改外部數據,如果方法調用者是struct,那么不會修改外部數據。
如果是數據的讀取,那么不管是指針還是struct,都能讀取到數據。
在換一個角度看,方法的調用者,在方法調用的時候,也進行了參數拷貝,所以可以認為方法調用者就是一個特殊的參數。

type person struct {id   intname stringage  int
}func (this person) GetNameS() string {return this.name
}func GetName(this *person) string {return this.name
}func TestPerson(t *testing.T) {p := person{id:   1,name: "zhangsan",age:  10,}fmt.Println(p.GetNameS())fmt.Println(GetName(&p))
}

運行都能獲取到結果
在這里插入圖片描述

只是無法使用.的方式觸發了。

4. 字段標簽

在Go語言的struct的字段后面,可以使用標簽。

type person struct {id   int    `tagKey:"tagValue1,tageValue2"`name string `tagKey:"tagValue1,tageValue2"`age  int    `tagKey:"tagValue1,tageValue2"`
}

4.1 Tag是Struct的一部分

Tag用于標識字段的額外屬性,類似注釋。標準庫reflect包中提供了操作Tag的方法。

// A StructField describes a single field in a struct.
type StructField struct {// Name is the field name.Name string// PkgPath is the package path that qualifies a lower case (unexported)// field name. It is empty for upper case (exported) field names.// See https://golang.org/ref/spec#Uniqueness_of_identifiersPkgPath stringType      Type      // field typeTag       StructTag // field tag stringOffset    uintptr   // offset within struct, in bytesIndex     []int     // index sequence for Type.FieldByIndexAnonymous bool      // is an embedded field
}

StructTag其實就是字符串:
在這里插入圖片描述

4.2 Tag 的約定

Tag本質上是個字符串,那么任何字符串都是合法的,但是在實際使用中,有一個約定:key:"value.."格式,如果有多個,中間用空格區分。

type person struct {id   int    `tagKey:"tagValue1,tageValue2" tagKey1:"tagValue1,tageValue2"`name string `tagKey:"tagValue1,tageValue2" tagKey1:"tagValue1,tageValue2"`age  int    `tagKey:"tagValue1,tageValue2" tagKey1:"tagValue1,tageValue2"`
}

key: 必須是非空字符串,字符串不能包含控制字符、空格、引號、冒號。
value: 以雙引號標記的字符串。
key和value之間使用冒號分割,冒號前后不能有空格。
多個key-value之間用空格分割。

key一般用于表示用途,value一般表示控制指令。
比如:
json:"name,omitempty"
表示json轉換的時候,使用name作為名字,如果字段值為空,那么json轉換該字段的時候忽略。

4.3 Tag 的獲取

reflectStructField提供了GetLookup方法:
在這里插入圖片描述

比如獲取上面person的Tag

func TestPerson(t *testing.T) {p := person{id:   1,name: "zhangsan",age:  10,}st := reflect.TypeOf(p)stf, ok := st.FieldByName("id")if !ok {fmt.Println("not found")return}nameTag := stf.Tagfmt.Printf("tagKey=%s\n", nameTag.Get("tagKey"))tagValue, ok := nameTag.Lookup("tagKey1")if !ok {fmt.Println("not found")return}fmt.Printf("tagKey1=%s\n", tagValue)
}

在這里插入圖片描述

在Java中有一個非常強大,也經常使用的插件lombok,通過在class的字段上添加注解,進而實現一些控制方法。
區別在于,lombok是在編譯時,通過操作字節碼,實現方法的寫入,而Tag是在運行時,通過反射賦值。
所以Tag只能操作已有的字段和函數,不能動態的增加或者減少字段和函數。
除了使用第三方庫,借助上述語法,自己也可以定義需要的操作比如判空。

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

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

相關文章

第二十三章 :Docker 部署 Redis

第二十三章 :Docker Redis 部署 Docker version 25.0.3, build 4debf41 ,Docker Compose version v2.24.2Redis-6.0.6 鏡像 redis:6.0.6-alpineRedis-6.0.6版本 部署規劃 服務器IP192.168.92.105端口6379安裝目錄/home/work/docker-redis-6.0.6數據映射目錄/home/work/do…

最簡單的基于 FFmpeg 的收流器(以接收 RTMP 為例)

最簡單的基于 FFmpeg 的收流器(以接收 RTMP 為例) 最簡單的基于 FFmpeg 的收流器(以接收 RTMP 為例)正文結果工程文件下載參考鏈接 最簡單的基于 FFmpeg 的收流器(以接收 RTMP 為例) 參考雷霄驊博士的文章…

藍凌OA frpt_listreport_definefield.aspx接口存在SQL注入漏洞

免責聲明:文章來源互聯網收集整理,請勿利用文章內的相關技術從事非法測試,由于傳播、利用此文所提供的信息或者工具而造成的任何直接或者間接的后果及損失,均由使用者本人負責,所產生的一切不良后果與文章作者無關。該…

DevStack 部署 OpenStack

Devstack 簡介 DevStack 是一系列可擴展的腳本,用于基于 git master 的最新版本快速調出完整的 OpenStack 環境。devstack 以交互方式用作開發環境和 OpenStack 項目大部分功能測試的基礎。 devstack 透過執行 stack.sh 腳本,搭建 openstack 環境&…

lv20 QT主窗口4

熟悉創建主窗口項目 1 QAction 2 主窗口 菜單欄:fileMenu menuBar()->addMenu(tr("&File")); 工具欄:fileToolBar addToolBar(tr("File")); 浮動窗:QDockWidget *dockWidget new QDockWidget(tr("Dock W…

Threejs之精靈模型Sprite

參考資料 精靈模型Sprite…Sprite模擬下雨、下雪 知識點 注:基于Three.jsv0.155.0 精靈模型Sprite精靈模型標注場景(貼圖)Sprite模擬下雨、下雪 精靈模型Sprite Three.js的精靈模型Sprite和Threejs的網格模型Mesh一樣都是模型對象,父類都是Object3…

【設計者模式】單例模式

文章目錄 1、模式定義2、代碼實現(1)雙重判空加鎖方式兩次判空的作用?volatile 關鍵字的作用?構造函數私有? (2)靜態內部類【推薦】(3)Kotlin中的單例模式lateinit 和 by…

Matlab 最小二乘插值(曲線擬合)

文章目錄 一、簡介二、實現代碼三、實現效果參考資料一、簡介 在多項式插值時,當數據點個數較多時,插值會導致多項式曲線階數過高,帶來不穩定因素。因此我們可以通過固定冪基函數的最高次數 m(m < n),來對我們要擬合的曲線進行降階。之前的函數形式就可以變為: 二、實現…

spring Boot 報錯RedisConnectionFailureException

錯誤描述&#xff1a; 錯誤重點&#xff1a;&#xff08;圖片中藍色區域&#xff09; Unable to connect to Redis; 無法連接到Redis Unable to connect to 127.0.0.1 無法連接到本地服務器 所以&#xff0c;錯誤是本地服務器沒有連接上Redis所引起的 錯誤解析…

vue3中的父傳子,子傳父

在Vue 3中&#xff0c;父組件向子組件傳遞數據和子組件向父組件通信的方式與Vue 2非常相似&#xff0c;但Vue 3提供了Composition API和更多的響應式API&#xff0c;為組件間的通信提供了更多的可能性。下面是父傳子和子傳父的基本方法&#xff1a; ### 父組件傳遞數據給子組件…

【InternLM 實戰營筆記】使用SDK接口上傳模型到OpenXLab

概述 浦源內容平臺-模型中心的Python SDK旨在為開發人員提供編程方式來管理和操作模型中心平臺的功能&#xff0c;以便他們可以輕松地與模型中心進行交互和模型管理。通過Python SDK提供的推理接口&#xff0c;開發人員能夠高效地調用不同的模型&#xff0c;實現模型應用的開發…

遞歸實現排列型枚舉(c++題解)

題目描述 把 1~n 這 n(n<10) 個整數排成一行后隨機打亂順序&#xff0c;輸出所有可能的次序。 輸入格式 一個整數n。 輸出格式 按照從小到大的順序輸出所有方案&#xff0c;每行1個。 首先&#xff0c;同一行相鄰兩個數用一個空格隔開。其次&#xff0c;對于兩個不同的…

Linux——進程控制(二)進程等待

目錄 前言 一、進程等待 二、如何進行進程等待 1.wait 2.waitpid 2.1第二個參數 2.2第三個參數 3. 等待多個進程 三、為什么不用全局變量獲取子進程的退出信息 前言 前面我們花了大量的時間去學習進程的退出&#xff0c;退出并不難&#xff0c;但更深入的學習能為本…

048 異常

什么是異常 異常體系結構 異常的繼承關系 Error Exception 異常處理機制 try&#xff1a;用{}將可能產生異常的代碼包裹catch&#xff1a;與try搭配使用&#xff0c;捕獲try包裹代碼中拋出的異常并進行后續動作finally&#xff1a;跟在try后&#xff0c;在try和catch之后執行…

web3時事粥報

比特幣正成為更具有吸引力的通脹對沖工具 在通脹的宏觀經濟浪潮中&#xff0c;比特幣正逐漸嶄露頭角&#xff0c;成為那些渴望多元化投資組合的投資者眼中的璀璨明星。Kooner 預測&#xff0c;2024年&#xff0c;各種宏觀經濟挑戰可能進一步提升比特幣、黃金和白銀等資產的避險…

3月3日做題總結(C/C++真題)

第一題 參加位運算的數據其類型不能是&#xff08;&#xff09;。 A---int B---char C---float D---long int 正確答案&#xff1a;C 解析&#xff1a;無論是float&#xff0c;還是double&#xff0c;在內存中的存儲分為三部分&#xff1a;符號位、指數位、尾數位&#…

Google Dremel和parquet的復雜嵌套數據結構表征方法解析

轉載請注明出處。作者&#xff1a;archimekai 核心參考文獻&#xff1a; Dremel: Interactive Analysis of Web-Scale Datasets 文章目錄 引言復雜嵌套數據結構的無損表征問題Dremel論文中提出的表征方法parquet備注 引言 Dremel是Google的交互式分析系統。Google大量采用prot…

全量知識系統問題及SmartChat給出的答復 之17 知識系統中的兩個特權類(超類和欠類) :腳本和場景

Q.45 知識系統中的兩個特權類 &#xff1a;腳本和場景 知識系統中的兩個特權類&#xff08;也是集合論中兩個特權集合&#xff09;&#xff1a;腳本script和場景scene 。 一個$Demonstrate類型的腳本script&#xff1a; 表示“值val”&#xff08; 形式上是應用程序的實用工…

如何學習openfoam

學習OpenFOAM的詳細步驟、流程、學習網站、練習案例以及B站學習資源推薦如下&#xff1a; 一、詳細步驟和流程 安裝OpenFOAM&#xff1a;首先&#xff0c;你需要在你的計算機上安裝OpenFOAM。你可以從OpenFOAM的官方網站下載適合你的操作系統的安裝包&#xff0c;然后按照官方提…

搭建服務器及跨域處理

使用內置的模塊搭建服務器 自己電腦: 域名:localhost ip:127.0.0.1 http模塊搭建服務器 const http = require(http)// 創建一個http對應的服務器,每次改完服務器的代碼后都需要重新啟動下服務器 /*方式一: const server = http.createServer((request,response)=>{…