目录

指针

1. &和*

Go语言也有指针的概念,取地址用&,根据地址取值用*,Go里面的指针是没有C语言中复杂的。

记住&后面是取地址。*是解引用。取的是指针的值.

1
2
3
4
5
6
n := 18
p := &n  // 取内存地址,16进制的数,切片的值可以变,但是内存地址不会变,记住的是第一个元素的内存地址
fmt.Printf("%v,%T\n", p, p) // 0xc0000aa058, *int
// 根据指针地址得到变量值
a := *p
fmt.Println(a)  // 18

2. new函数

1
2
3
4
5
6
7
8
9
func main() {
	var a *int              // 这个是没有内存地址的,如果打印*a,会引发panic
	fmt.Println(a)          // <nil>

	var a1 = new(int)       // 是有内存地址的,new函数申请一个内存地址
	fmt.Println(a1, *a1)    // 0xc000014120 0
	*a1 = 100
	fmt.Println(a1, *a1)    // 0xc000014120 100
}
注意点
  • new有时候也用, 但大多数用make的居多。可以看一下go源码里面new是怎么使用的

  • 记得,new函数申请的是一个地址!

3. new和make的区别

new和make的区别
  • make和new都是用来申请内存的
  • new很少用,一般用来给基本数据类型申请内存,string,int等返回的是对应类型的指针,*string,*int
  • make用于也只能用于给slice、map、chan申请内存,make函数返回的是这三个类型本身,而不是他们的指针类型,因为这三张类型就是引用类型,所以就没必要返回他们的指针了

4.注意点

我在编写的时候遇到这样一道代码, 这段代码取自go黑帽子编程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var (
		flDomain      = flag.String("domain", "", "The domain to perform guessing against.")
		flWordlist    = flag.String("wordlist", "", "The wordlist to use for guessing.")
		flWorkerCount = flag.Int("c", 100, "The amount of workers to use.")
		flServerAddr  = flag.String("server", "8.8.8.8:53", "The DNS server to use.")
	)
flag.Parse()

if *flDomain == "" || *flWordlist == "" {
	fmt.Println("-domain and -wordlist are required")
	os.Exit(1)
}

var results []result

fqdns := make(chan string, *flWorkerCount)
gather := make(chan []result)
tracker := make(chan empty)

flag函数返回的类型是*int等。我们在用的时候,加了一个*, 就是解引用。这样就能取到对应的值和类型了。下次遇到了不要再不会了!

操作指针的时候是解引用,记住下面的规律。

规律
1
2
3
4
&int => *int 
*(&int) => int 
&(*int) => **int 
*(&(&int)) => *int

下面的之所以*a1,是因为a1本身就是一个地址啊!*int类型的!

1
2
3
4
var a1 = new(int)  // 是有内存地址的,new函数申请一个内存地址
fmt.Println(a1, *a1)
*a1 = 100
fmt.Println(a1, *a1)

上面两种写法要记得!本质上都是 * (*int)进行解引用。