簽名我們瞭解了一些golang的基礎知識,可以明確的發現golang和c語言很是類似,那麼看到這裡,你可能更加震驚,這可能就是個新時代的c語言。
指標
變數是一種使用方便的佔位符,用於引用計算機記憶體地址。 Go 語言的取地址符是 &,放到一個變數前使用就會返回相應變數的記憶體地址。
示例程式碼如下:
package main
import "fmt"
func main() {
var a int = 10
fmt.Printf("變數的地址: %x\n", &a )
}
複製程式碼
輸出結果如下,可能這裡不同的電腦有一些不同的輸出結果:
變數的地址: c420014058
複製程式碼
指標的概念是:指向任何一個值的記憶體地址,是記憶體地址的編號。重點:
- 是go中基本資料型別
- 代表記憶體地址
- 可以指向任意資料的地址
- 不同資料型別的指標需要不同的資料型別和指標符號組合來表示
我們來看看簡單的一些例項:
//指標申明格式
// var var_name *var-type
// var-type 為指標型別,var_name 為指標變數名,* 號用於指定變數是作為一個指標。
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮點型 */
複製程式碼
指標和其他型別的變數一樣,我們需要申明和賦值後才能使用,看看下面的demo:
package main
import "fmt"
func main() {
var a int = 20 /* 宣告實際變數 */
var aPointer *int /* 宣告指標變數 */
aPointer = &a /* 指標變數的儲存地址 */
fmt.Printf("a 變數的地址是: %x\n", &a)
/* 指標變數的儲存地址 */
fmt.Printf("aPointer 變數儲存的指標地址: %x\n", aPointer)
/* 使用指標訪問值 */
fmt.Printf("*aPointer 變數的值: %d\n", *aPointer)
}
複製程式碼
輸出結果如下(不同電腦可能實際地址不同):
a 變數的地址是: c420014050
aPointer 變數儲存的指標地址: c420014050
*aPointer 變數的值: 20
複製程式碼
其實關於指標更加詳盡的用法可以看看大學c語言教材,以及資料結構c語言版。
空指標
當一個指標被定義後沒有分配到任何變數時,它的值為 nil。
nil 指標也稱為空指標。
nil在概念上和其它語言的null、None、nil、NULL一樣,都指代零值或空值。
一個指標變數通常縮寫為 ptr。
注意,指標還有以下操作:
- 指標陣列(核心是陣列和指標)
- 多級指標(指向指標的指標)
- 函式的指標引數
我們來看看下面的例子:
package main
import "fmt"
func main() {
var a int = 20 /* 宣告實際變數 */
var aPointer *int /* 宣告指標變數 */
aPointer = &a /* 指標變數的儲存地址 */
fmt.Printf("a 變數的地址是: %x\n", &a)
/* 指標變數的儲存地址 */
fmt.Printf("aPointer 變數儲存的指標地址: %x\n", aPointer)
/* 使用指標訪問值 */
fmt.Printf("*aPointer 變數的值: %d\n", *aPointer)
b := 35
bPointer := &b
fmt.Printf("a = %d ,b = %d \n", a, b)
fmt.Printf("aPointer = %x ,bPointer = %x \n", aPointer, bPointer)
swap(aPointer, bPointer)
fmt.Println("交換後的結果")
fmt.Printf("a = %d ,b = %d \n", a, b)
fmt.Printf("aPointer = %x ,bPointer = %x \n", aPointer, bPointer)
pBPtr := &bPointer
fmt.Printf("pBPtr = %x ,*pBPtr = %x ,**pBPtr = %x \n", pBPtr, *pBPtr, **pBPtr)
}
func swap(a, b *int) {
tmp := *a
*a = *b
*b = tmp
}
複製程式碼
輸出的結果是hi:
a 變數的地址是: c420014050
aPointer 變數儲存的指標地址: c420014050
*aPointer 變數的值: 20
a = 20 ,b = 35
aPointer = c420014050 ,bPointer = c420014060
交換後的結果
a = 35 ,b = 20
aPointer = c420014050 ,bPointer = c420014060
pBPtr = c42000c030 ,*pBPtr = c420014060 ,**pBPtr = 14
複製程式碼
在上面的例子中,我們可以明顯的看到a、b的值在交換後發生了變化,但是aPointer和bPointer的值並沒有發生變化。
在交換函式中,我們把a、b的值通過指標操作的方式直接更改了,但是aPointer和bPointer是指向了a、b的地址,我們並沒有改變他們,則有aPointer和bPointer值沒有變化。
接著我們申明並且初始化了一個二級指標pBPtr,他的值是bPointer這個指標變數的地址,接著*pBPtr的值是bPointer指向的地址也即是b的地址,所以**pBPtr的值是b的值。
結構體
結構體,和我們在c語言中遇到的一樣,用來將不同資料(無論資料型別是否相同)組裝在一起。在其他的面嚮物件語言中,比如說java,我們習慣來寫bean物件,如下:
//在java中建立Person實體
class Person implements Serializable{
private String name;
private Integer age;
}
複製程式碼
那麼我們在go中如何操作呢?
type Person struct {
name string
age int
}
複製程式碼
當然,我們不妨看看具體demo:
package main
import "fmt"
type Person struct {
name string
age int
}
//這裡是方法,輸入Person的方法
func (person Person) logPerson() {
fmt.Printf("%s,年齡:%d", person.name, person.age)
}
func main() {
var aPerson Person
aPerson.name = "go語言"
aPerson.age = 8
aPerson.logPerson()
}
複製程式碼
在上面的程式碼中,我們使用了一些知識點:
- 變數,申明和賦值
- 包名、導包、主函式
- 函式、方法
- 結構體
我們再主函式中,申明瞭aPerson變數,且資料型別是結構體Person。然後我們針對結構體的具體屬性進行了初始化,然後呼叫結構體自身的方法實現了列印Person的相關資訊。
當然結構體有一些以下操作:
- 屬性訪問,結構體變數名.屬性名
- 類似基本資料型別的使用方法(申明變數、函式引數、指標等)
下面的demo基本闡述了結構體的常規用法:
package main
import "fmt"
type Person struct {
name string
age int
}
func (person Person) logPerson() {
fmt.Printf("%s,年齡:%d \n", person.name, person.age)
}
func printPersonByPointer(person *Person) {
fmt.Printf("%s,年齡:%d \n", person.name, person.age)
}
func printPerson(person Person) {
fmt.Printf("%s,年齡:%d \n", person.name, person.age)
}
func main() {
var aPerson Person
aPerson.name = "go語言"
aPerson.age = 8
aPerson.logPerson()
printPersonByPointer(&aPerson)
printPerson(aPerson)
}
複製程式碼
注意:在go語言中,不支援函式過載
總結
go語言和c語言又很多類似的地方。指標和結構體都是c語言中類似的概念。
- 指標支援任意資料型別的操作,指標申明格式為:var *name dataType
- 指標儲存記憶體地址,&是取變數的地址,*是取指標指向記憶體的值
- 多級指標的層級
- 結構體可以稱之為擴充套件資料型別或包裝資料型別
- 結構體用於定義非基本資料型別
- 結構體的基本操作(屬性讀寫、函式引數、結構體指標)
如果你認可我所做的事情,並且認為我做的事對你有一定的幫助,希望你也能打賞我一杯咖啡,謝謝。