刚学习golang的人可能不是很明白普通变量和指针的区别,看到有人说其实普通变量是程序创造出来的,比如说 c 中:

 a int 

  那么在编译时 就会有 [a 地址 int] 这样来标识内存。

  普通变量 a 其实是语言本身创造了,是为了更方便的表示内存。我们对a进行访问其实就是直接对内存进行访问。至于 a 表示的内存的地址是多少,程序员一般不用关心。编译器会自动分配地址,也就是常说的为 a 分配一个地址。如果想知道 a 的地址也可以通过 &a 得知。

  打个比方来理解:普通变量就像是房间(内存)外面的门牌号(总经理室),指针就是这个房间的地址(9#905)。

  变量是运行时系统给这个内存起的别名,内存地址是唯一的,程序中当我想拿到这个内存的值的时候,因为知道它的别名,所以直接用别名访问就可以得到值,又或者我能知道它唯一的地址我也能得到它的值,其实是两种不同的内存访问方式,但是变量是会变的,地址是不会变的。比如在go中:

package main
 
func main(){
    a := 10   //此时有一块内存存放了10,它的地址由系统自动分配,别名是a
    a = 20   //内存存放的10变成了20
    var p *int
    p = &a   //或者直接写 p := &a
    //上面的p是一个指针,通过 *p 的方式同样可以访问 变量a指向 的内存
 
    /*当你动态申请内存的时候,指针的存在意义之一就被体现出来了*/ 
    ptr := new(int)   
    //申请了一块内存空间,没有办法指定别名,new()返回内存地址,用指针接收
    //此时并没有变量能直接指向这块内存,所以只能通过内存地址来访问
}

  看到有个解释还可以,是说指针和普通变量区别的:

    1. 1+2这个表达式永远得值3。
    2. a+b这个表达式只依赖于a,b的值—–按名字访问称为直接访问。
    3. *p + *q 这个表达式的值随着p,q指向的变量不同而不同—-按指针访问称为间接访问。

三、指针的使用

  方法中的指针。方法即为有接受者的函数,接受者可以是类型的实例变量或者是类型的实例指针变量。但两种效果不同。

1、类型的实例变量

func main(){
    person := Person{"TigerwolfC", 25}
    fmt.Printf("person<%s:%d>\n", person.name, person.age)
    person.sayHi()
    person.ModifyAge(28)
    person.sayHi()
}
type Person struct {
    name string
    age int
}
func (p Person) sayHi() {
    fmt.Printf("SayHi -- This is %s, my age is %d\n",p.name, p.age)
}
func (p Person) ModifyAge(age int) {
    fmt.Printf("ModifyAge")
    p.age = age
}

  输出结果:

person<TigerwolfC:25>
SayHi -- This is TigerwolfC, my age is 25
ModifyAgeSayHi -- This is TigerwolfC, my age is 25

  尽管 ModifyAge 方法修改了其 age 字段,可是方法里的 p 是 person 变量的一个副本,修改的只是副本的值。下一次调用 sayHi 方法的时候,还是 person 的副本,因此修改方法并不会生效。即实例变量的方式并不会改变接受者本身的值。

package main
 
import "fmt"
 
func main(){
    person := Person{"TigerwolfC", 25}
    fmt.Printf("person<%s:%d>\n", person.name, person.age)
    person.sayHi()
    person.ModifyAge(28)
    person.sayHi()
}
 
type Person struct {
    name string
    age int
}
 
func (p *Person) sayHi() {
    fmt.Printf("SayHi -- This is %s, my age is %d\n",p.name, p.age)
}
 
func (p *Person) ModifyAge(age int) {
    fmt.Printf("ModifyAge")
    p.age = age
}
person<TigerwolfC:25>
SayHi -- This is TigerwolfC, my age is 25
ModifyAgeSayHi -- This is TigerwolfC, my age is 28
func main(){
    // 声明一个指针变量 aPot 其类型也是 string
    var aPot *string
    fmt.Printf("aPot: %p %#v\n", &aPot, aPot) // 输出 aPot: 0xc42000c030 (*string)(nil)
    *aPot = "This is a Pointer"  // 报错: panic: runtime error: invalid memory address or nil pointer dereference
}
  var aPot *string
  fmt.Printf("aPot: %p %#v\n", &aPot, aPot) // 输出 aPot: 0xc42000c030 (*string)(nil)
  aPot = &aVar
  *aPot = "This is a Pointer"
  fmt.Printf("aVar: %p %#v \n", &aVar, aVar) // 输出 aVar: 0xc42000e240 "This is a Pointer"
  fmt.Printf("aPot: %p %#v %#v \n", &aPot, aPot, *aPot) // 输出 aPot: 0xc42000c030 (*string)(0xc42000e240) "This is a Pointer"
var aNewPot *int
aNewPot = new(int)
*aNewPot = 666
fmt.Printf("aNewPot: %p %#v %#v \n", &aNewPot, aNewPot, *aNewPot) // 输出 aNewPot: 0xc42007a028 (*int)(0xc42006e1f0)