golang方法(method)返回值提取結(jié)構(gòu)體(struct)取不到地址的原因是,①返回值并沒有保存到變量中,返回值本身只是臨時保存在程序運行的堆棧的某個不確定位置,不能取地址;②實參取地址用的操作符是是,而形參聲明變量類型為指針,需要地址值用的才是*;③聲明形參為指針的參數(shù)的實參只能為地址值。
創(chuàng)新互聯(lián)建站專注于坪山企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),成都做商城網(wǎng)站。坪山網(wǎng)站建設(shè)公司,為坪山等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站建設(shè),專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務(wù)
故先把修改后的代碼列出,修改要點是把“*NewPerson1().Speak()”改為“var b=NewPerson1();(b).Speak()”,同時把“NewPerson2().Speak()”改成“var a=NewPerson2();(a).Speak()”,代碼列出如下:
package main;
import "fmt";
type PersonA struct{
name string
}
func (p *PersonA) Speak () {
fmt.Println ( "person speak" ,p.name)
}
func (p PersonA) Walk ( ){
fmt . Println ( "person walk",p.name)}
func NewPerson1()(p PersonA){
return PersonA{"new Person1"}}
func NewPerson2()(p PersonA){
return PersonA{"new Person2"}}
func main () {
var a=NewPerson2 (); (a).Speak ();?
a .Walk ();
fmt. Println ("--------------------")?;
var b=NewPerson1 ();(b).Speak ();
b.Walk ()}
go代碼調(diào)試效果
關(guān)于指針變量的使用這一點go語言和其他有指針的程序語言如c語言是一樣的,從來只有返回值為地址/指針,而從沒有在賦值前給返回值取地址這種運算,類似的錯誤晚點再整理。
不一樣的是,go語言更簡單go語言函數(shù)可以使用結(jié)構(gòu)體或者結(jié)構(gòu)體的指針(pointer)以傳遞結(jié)構(gòu)體參數(shù),而且和c語言不一樣的是,go語言沒有區(qū)分結(jié)構(gòu)體指針和結(jié)構(gòu)體訪問成員的運算符,go語言只有“.”適用于兩種情況,而沒有c語言為結(jié)構(gòu)體指針專門準(zhǔn)備的“-”運算符。
可以使用結(jié)構(gòu)體指針,作為結(jié)構(gòu)體的方法的參數(shù)以指代自身嗎,
設(shè)結(jié)構(gòu)體struct A:
#define NAME_SIZE????? 20
struct A{
int val;
char name[NAME_SIZE];
};
// 定義2個結(jié)構(gòu)體對象
A a1, a2;
賦值方法
1. 利用庫函數(shù)memcpy (頭文件string.h), 可以對結(jié)構(gòu)體對象整體賦值.
memcpy(a2, a1, sizeof a2); // = a2 = a1
2. 對每個成員單獨進(jìn)行賦值
a2.val = a1.val;
for (int i = 0; i NAME_SIZE; ++i)
a2.name[i] = a1.name[i];
作為C語言家族的一員,go和c一樣也支持結(jié)構(gòu)體??梢灶惐扔趈ava的一個POJO。
在學(xué)習(xí)定義結(jié)構(gòu)體之前,先學(xué)習(xí)下定義一個新類型。
新類型 T1 是基于 Go 原生類型 int 定義的新自定義類型,而新類型 T2 則是 基于剛剛定義的類型 T1,定義的新類型。
這里要引入一個底層類型的概念。
如果一個新類型是基于某個 Go 原生類型定義的, 那么我們就叫 Go 原生類型為新類型的底層類型
在上面的例子中,int就是T1的底層類型。
但是T1不是T2的底層類型,只有原生類型才可以作為底層類型,所以T2的底層類型還是int
底層類型是很重要的,因為對兩個變量進(jìn)行顯式的類型轉(zhuǎn)換,只有底層類型相同的變量間才能相互轉(zhuǎn)換。底層類型是判斷兩個類型本質(zhì)上是否相同的根本。
這種類型定義方式通常用在 項目的漸進(jìn)式重構(gòu),還有對已有包的二次封裝方面
類型別名表示新類型和原類型完全等價,實際上就是同一種類型。只不過名字不同而已。
一般我們都是定義一個有名的結(jié)構(gòu)體。
字段名的大小寫決定了字段是否包外可用。只有大寫的字段可以被包外引用。
還有一個點提一下
如果換行來寫
Age: 66,后面這個都好不能省略
還有一個點,觀察e3的賦值
new返回的是一個指針。然后指針可以直接點號賦值。這說明go默認(rèn)進(jìn)行了取值操作
e3.Age 等價于 (*e3).Age
如上定義了一個空的結(jié)構(gòu)體Empty。打印了元素e的內(nèi)存大小是0。
有什么用呢?
基于空結(jié)構(gòu)體類型內(nèi)存零開銷這樣的特性,我們在日常 Go 開發(fā)中會經(jīng)常使用空 結(jié)構(gòu)體類型元素,作為一種“事件”信息進(jìn)行 Goroutine 之間的通信
這種以空結(jié)構(gòu)體為元素類建立的 channel,是目前能實現(xiàn)的、內(nèi)存占用最小的 Goroutine 間通信方式。
這種形式需要說的是幾個語法糖。
語法糖1:
對于結(jié)構(gòu)體字段,可以省略字段名,只寫結(jié)構(gòu)體名。默認(rèn)字段名就是結(jié)構(gòu)體名
這種方式稱為 嵌入字段
語法糖2:
如果是以嵌入字段形式寫的結(jié)構(gòu)體
可以省略嵌入的Reader字段,而直接訪問ReaderName
此時book是一個各個屬性全是對應(yīng)類型零值的一個實例。不是nil。這種情況在Go中稱為零值可用。不像java會導(dǎo)致npe
結(jié)構(gòu)體定義時可以在字段后面追加標(biāo)簽說明。
tag的格式為反單引號
tag的作用是可以使用[反射]來檢視字段的標(biāo)簽信息。
具體的作用還要看使用的場景。
比如這里的tag是為了幫助 encoding/json 標(biāo)準(zhǔn)包在解析對象時可以利用的規(guī)則。比如omitempty表示該字段沒有值就不打印出來。
1,右值不可賦值
2,函數(shù)返回的是右值
getTest()是右值,結(jié)構(gòu)體整體都是右值,右值不可賦值
getTestPoint()返回當(dāng)然也是右值,但只有指針是右值,即你不能給返回的指針賦值(例如:getTestPoint() = nil),但是可以給指針指向的結(jié)構(gòu)體成員賦值(就像你代碼里那樣)
有右值自然就有左值,左值是可被賦值的,例如
t := getTest() //getTest() 返回的右值,賦值給左值t
t.test = 1,左值可被賦值
結(jié)構(gòu)體變量簡稱為結(jié)構(gòu)變量,它由結(jié)構(gòu)類型定義,有三種定義方法。下面以定義結(jié)構(gòu)類型 book 和結(jié)構(gòu)變量mybook 、 storybook 為例說明之。
1. 先定義結(jié)構(gòu)類型,再定義結(jié)構(gòu)變量。
struct book /* 定義結(jié)構(gòu)體類型 */
{
char bookname[20];
float price;
char publisher[20];
char author[10];
} ;
struct book mybook, storybook;
用這種方法定義結(jié)構(gòu)變量,是最常用的方法,但須注意不能省略關(guān)鍵字“ struct ”。還可以在定義結(jié)構(gòu)變量的同時給它的成員賦初值。如:
struct book /* 定義結(jié)構(gòu)體類型 */
{
char bookname[20];
float price;
char publisher[20];
char author[10];
} ;
struct book mybook = { “maths”, 24.7, “ 電子社 ”, “zhao” }, storybook;
則, mybook 變量的 price = 24.7 。
2. 定義結(jié)構(gòu)類型的同時定義結(jié)構(gòu)變量。
struct book /* 定義結(jié)構(gòu)體類型 */
{
char bookname[20];
float price;
char publisher[20];
char author[10];
} struct book mybook, storybook;
3. 不定義結(jié)構(gòu)類型,直接定義結(jié)構(gòu)變量。
struct /* 不定義結(jié)構(gòu)類型名 */
{
char bookname[20];
float price;
char publisher[20];
char author[10];
} struct book mybook, storybook;
需要說明的是,當(dāng)某結(jié)構(gòu)類型的成員又是另外一個結(jié)構(gòu)類型時,稱嵌套定義,其定義方法如下:
struct brith_date
{
int month ;
int day ;
int year ;
} ;
struct
{
char name[10] ;
char address[30];
char tel[12];
int age;
struct data birthday;
char sex[3];
} student_01 , employee ;
此例直接定義了 student_01 和 employee 兩個變量,但是沒有定義此結(jié)構(gòu)體的名字,因此不能再定義與student_01 和 employee 同類的其它結(jié)構(gòu)變量了!如下行定義是錯誤的:
truct boy, girl;
c里面是不能這樣賦值的, 這種方式只有在定義的時候初始化才可以
如果 int a[][2] = { 2,2}這是正確的,但是定義數(shù)組之后再 a = { 2,2}是不正確的, 你還是一個一個賦值吧. 另外說明一下吧, 定義的時候是給變量申請內(nèi)存, 編譯器會把你初始話的值賦值到內(nèi)存, 但是如果 以后在賦值的時候, 就成了指針了, 語法就不正確了
m1-edges=
{
{0,1,0,0},
{1,0,1,0},
{0,1,0,1},
{0,0,1,0}
};
------
你可以把你要初始話的這個數(shù)組定義個const數(shù)組, 后面再用for來賦值吧, 沒有其他辦法
{
{0,1,0,0},
{1,0,1,0},
{0,1,0,1},
{0,0,1,0}
};