Go基础|第6章:pointer

  • 原创
  • Madman
  • /
  • /
  • 0
  • 4162 次阅读

Golang.jpg

Synopsis: Go 语言提供了指针。指针是一种直接存储了值的内存地址的数据类型。& 操作符可以返回一个变量的内存地址,并且 * 操作符 可以获取指针指向的变量内容,但是在 Go 语言里没有指针运算

1. 指针类型

A pointer is a variable that contains the address of a value.

对于每一个变量必然有对应的内存地址(变量有时候也被称为可寻址的值),通过 指针 我们可以直接读取或更新对应变量的值,而无需知道该变量的名字。Go 语言使用 值传递,如果考虑效率的话,较大的 struct 通常会用 指针 的方式传递给函数形参和返回

*T 类型表示指向 T 类型值的 指针,其零值为 nil

var p *int  // 声明一个 [指向 int 类型的指针] p,并初始化为其零值 nil

指向不同类型的指针不能互相比较:

var p1 *int
var p2 *float32
fmt.Println(p1 == p2)  // invalid operation: p1 == p2 (mismatched types *int and *float32)

或赋值:

package main

import (
  "fmt"
)

func main() {
  var p1 *int
  var p2 *float32

  i := 10
  p1 = &i
  fmt.Printf("%T, %#v \n", p1, p1)

  // p2 = p1 // cannot use p1 (type *int) as type *float32 in assignment
  fmt.Printf("%T, %#v", p2, p2)
}

/* Output:
*int, (*int)(0xc0000100a0)
*float32, (*float32)(nil)
*/

2. 地址操作符: &

& 操作符会生成一个指向其操作数的指针:

i := 10  // i holds the actual int
p := &i  // p holds the address of the int
package main

import "fmt"

func main() {
  i := 10
  p := &i  // 指针 p 指向 i
  fmt.Printf("%T, %v", p, p)
}

/* Output:
*int, 0xc00000a0b8
*/

3. 间接引用操作符: *

* 操作符表示指针指向的变量的值:

fmt.Println(*p) // 间接引用,通过指针 p 读取 i
*p = 21         // 间接引用,通过指针 p 设置 i

当使用指针修改变量时,所有使用该变量的地方都会看到变化。另外,与 C 不同,Go 没有指针运算

4. new() 函数创建指针

创建指针的方式除了

var p *int

i := 10
p := &i

以外,还可以使用内建函数 new(T),它会创建 T 类型的匿名变量(初始化为 T 类型的零值),并返回变量地址:

// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type
package main

import "fmt"

func main() {
  var p = new(int)
  fmt.Printf("%T, %v \n", p, p)
  fmt.Printf("*p 表示指针 p 所指向的变量的值: %T, %v", *p, *p)
}

/* Output:
*int, 0xc00000a0b8
*p 表示指针 p 所指向的变量的值: int, 0
 */

5. panic: nil pointer dereference

由于 *T 类型指针 p 的零值为 nil,此时执行 *p 将导致运行时 panic 异常:

package main

import (
  "fmt"
)

func main() {
  var p *int
  fmt.Printf("%T, %#v\n", p, p) // Output: *int, (*int)(nil)

  *p = 10  // 想通过指针 p 设置值,panic: runtime error: invalid memory address or nil pointer dereference
  fmt.Printf("%T, %#v", p, p)
}

可以修改为:

package main

import (
  "fmt"
)

func main() {
  var i int
  var p *int
  fmt.Printf("%T, %#v\n", p, p)

  p = &i // p is no longer nil
  fmt.Println(i)
  fmt.Printf("%T, %#v\n", p, p)

  *p = 10
  fmt.Println(i)
  fmt.Printf("%T, %#v", p, p)
}

/* Output:
*int, (*int)(nil)
0
*int, (*int)(0xc000014098)
10
*int, (*int)(0xc000014098)
*/

6. 指针比较

任何类型的指针的零值都是 nil

package main

import (
  "fmt"
)

func main() {
  var p1, p2 *int
  var p3 *float64

  fmt.Printf("%T, %#v \n", p1, p1)
  fmt.Printf("%T, %#v \n", p2, p2)
  fmt.Printf("%T, %#v \n\n", p3, p3)

  fmt.Println(p1 == nil)
  fmt.Println(p2 == nil)
  fmt.Println(p3 == nil)
}

/* Output:
*int, (*int)(nil)
*int, (*int)(nil)
*float64, (*float64)(nil)

true
true
true
 */

但是一旦指针 p 指向了某个有效的变量时,那么 p == nil 表达式的值为 false:

package main

import (
  "fmt"
)

func main() {
  var p1, p2 *int
  var p3 *float64

  fmt.Printf("%T, %#v \n", p1, p1)
  fmt.Printf("%T, %#v \n", p2, p2)
  fmt.Printf("%T, %#v \n\n", p3, p3)

  a, b := 0, 0  // a 和 b 的值相同,但内存地址不同
  c := 3.14

  p1 = &a  // 指针指向了有效变量后就不是 nil 了
  p2 = &b
  p3 = &c

  fmt.Printf("%T, %#v \n", p1, p1)
  fmt.Printf("%T, %#v \n", p2, p2)
  fmt.Printf("%T, %#v \n\n", p3, p3)

  fmt.Println(p1 == nil)
  fmt.Println(p2 == nil)
  fmt.Println(p3 == nil)
}

/* Output:
*int, (*int)(nil)
*int, (*int)(nil)
*float64, (*float64)(nil)

*int, (*int)(0xc0000a0068)
*int, (*int)(0xc0000a0080)
*float64, (*float64)(0xc0000a0088)

false
false
false
*/

指针之间可以进行相等测试(必须是相同的 *T),只有当它们 指向同一个变量全部是 nil 时才相等:

package main

import (
  "fmt"
)

func main() {
  var x, y int // x 和 y 都被初始化整形的零值 0,但内存地址不同

  p1 := &x // 指针指向了有效变量后就不是 nil 了
  p2 := &y

  fmt.Printf("%T, %#v \n", p1, p1)
  fmt.Printf("%T, %#v \n\n", p2, p2)

  fmt.Println(p1 == &x)  // 指向同一个变量,或者 fmt.Println(&x == &x)
  fmt.Println(&x == &y)  // 或者 fmt.Println(p1 == p2)
  fmt.Println(p1 == nil) // 或者 fmt.Println(&x == nil)
}

/* Output:
*int, (*int)(0xc0000a0068)
*int, (*int)(0xc0000a0080)

true
false
false
*/
分类: Go Basic
标签: * & *T new()
未经允许不得转载: LIFE & SHARE - 王颜公子 » Go基础|第6章:pointer

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.