go语言指针速通

1、go语言指针概述

go语言指针,其实就是Java中引用类型(区别于基本类型)的底层原理,涉及到内存结构,Java中的内存有堆栈方法区,而go语言中因为逃逸分析的存在,所以值类型和引用类型存放于堆栈是不一定的,编译器会自动优化,有利于减少垃圾产生,减少GC,同时减少程序员的负担。

2、go语言指针入门

理解go语言指针,只需要记住两个符号:*和&。

&很简单,就是取地址。
*的意思的取值,注意,这里有四种使用场景。
场景一:用在类名前面,构成新的引用类型的类。
场景二:用在变量名前面,同时变量位于赋值号左边。
场景三:用在变量名前面,同时变量位于赋值号右边。
场景四:用在变量名前面,同时变量作为参数或接收体。

场景二是给变量赋值,这个值一定是某个变量的地址。
场景三是取出变量的值参与运算。
场景四能够让变量本身的值发生改变。

试着实现以下需求:

1、取出值类型的地址。
2、把值类型的地址存在一个引用类型变量中。
3、取出引用类型的值的地址。
4、取出引用类型的值和地址。
5、把引用类型的变量的值进行更改。
6、两个不同引用类型变量指向同一个内存地址的值。
7、把引用类型变量的值取出来参与运算。

package main

import "fmt"

func main(){
	//1、取出值类型的地址。
	var a int = 13
	fmt.Println("0、定义变量并赋值:a = ",a)
	fmt.Println("1、取出值类型的地址: &a = ",&a)
	//2、把值类型的地址存在一个引用类型变量中。
	var b *int = &a
	fmt.Println("2、把值类型的地址存在一个引用类型变量中:","var b *int = &a")
	//3、取出引用类型的值的地址。
	fmt.Println("3、取出引用类型的值的地址: b = ",b)//值的地址

	//4、取出引用类型的值和地址。
	fmt.Println("4.1、取出引用类型的值: *b = ",*b)//值
	fmt.Println("4.2、取出引用类型的地址: &b = ",&b)//地址

	//5、把引用类型的变量的值进行更改。
	*b = 16
	fmt.Println("5、把引用类型的变量的值进行更改: "," a = ",a,"; *b = ",*b)
	//6、两个不同引用类型变量指向同一个内存地址的值。
	var c *int = b
	var d *int = &a
	if(c==d&&b==d){
		fmt.Println("6、两个不同引用类型变量指向同一个内存地址的值:","b、c、d他们都一样。")
	}
	//7、把引用类型变量的值取出来参与运算。
	var e int = *b*3
	fmt.Println("7、把引用类型变量的值取出来参与运算: e = *b*3 = ",e)
}

以上代码打印结果为:

0、定义变量并赋值:a = 13
1、取出值类型的地址: &a = 0xc00000a0a8
2、把值类型的地址存在一个引用类型变量中: var b *int = &a
3、取出引用类型的值的地址: b = 0xc00000a0a8
4.1、取出引用类型的值: *b = 13
4.2、取出引用类型的地址: &b = 0xc000006030
5、把引用类型的变量的值进行更改: a = 16 ; *b = 16
6、两个不同引用类型变量指向同一个内存地址的值: b、c、d他们都一样。
7、把引用类型变量的值取出来参与运算: e = b3 = 48

3、函数中的指针

以下示例可帮助理解函数中的指针:

package main
import "fmt"

func changeValue(p int){
	p = 10
}

func main(){
	var a int = 2
	changeValue(a)
	fmt.Println("a = ",a)
}
//打印出来a = 2
//这是因为函数调用时是值传递,
//changeValue函数调用完毕没有返回值,
//所以把2传进去自己玩了一把寂寞,然而并没有什么卵用。

如果想实现:把a传进去,修改的就是a本身的值,怎么做?
用指针,引用传递,见如下代码:

package main

import "fmt"

func changeValue(p *int){
//*int是一种区别于int的类型,
//用以存int值的内存地址
	*p = 10//如果p = 10,表示把p的值修改为10
	//*p = 10   *是取值符,表示找到p表示的地址指向的内存的值修改为10
}

func main(){
	var a int = 2
	changeValue(&a)
	fmt.Println("a = ",a)//打印出来 a = 10
}

4、复杂类型对象如何取地址?

 	var r1 *Rect//Rect是自定义的结构体
    r1 = &Rect{100,200}
    fmt.Println("值的地址:r1 = ",r1)
    fmt.Println("值:*r1 = ", *r1)
    fmt.Println("引用的地址:&r1 = ", &r1)

这段我打印出来是:

值的地址:r1 = &{100 200}
值:*r1 = {100 200}
引用的地址:&r1 = 0xc000006030

问题:这个 &{100 200}到底是什么地址?
答:可以用Printf("%p",r1)拿到r1的值的地址。

问题:引用的地址是什么鬼?
答:引用就是指针,就是存地址的变量,他本身也有地址。

 	var r1 *Rect
    r1 = &Rect{100,200}
    fmt.Printf("r1值的地址:%p\n",r1)
    //打印结果:r1值的地址:0xc00000a0a8

5、指针与面向对象

实现以下需求:
1、创建学生类、老师类
2、给每个类写一个构造方法,一个成员方法。
3、实例化一个学生,一个老师。
tip:学生类中有一个引用类型属性;
学生类构造方法创造引用类型,老师类构造方法创造值类型;

package main

import "fmt"

func main(){
	var college *string
	var str string
	str = "北京大学"
	college = &str
	//实例化一个学生
	stu := newStu("张楚岚", 16, 10086, college)
	stu.selfIntro()
	
	//实例化一个老师
	t1 := newTeacher("冯宝宝",200,999999999)
	t1.speak()
}

type student struct{
	name string
	age int
	stuId int
	college *string
}

type teacher struct{
	name string
	age int
	salary float32
}



/*学生类构造方法*/
func newStu(name string,age int,stuId int,college *string) *student{
	//因为返回值类型*student是引用类型,所以下面要用&把地址取出来赋值返回
	s := &student{
		name,
		age,
		stuId,
		college,
	}
	return s
}
/*老师类构造方法*/
func newTeacher(name string,age int,salary float32) teacher{
	//因为返回值类型teacher是值类型,所以下面直接赋值返回
	t :=teacher{
		name,
		age,
		salary,
	}
	return t
}
/*学生类成员方法*/
func(stu *student)selfIntro(){
	fmt.Println("My name is",stu.name,",I graduated from",*stu.college)
}
/*老师类成员方法*/
func(t *teacher)speak(){
	fmt.Println("I am",t.name)
}

6、项目中的指针示例

理解如下代码:
1、把 *类放在接收体中。(类成员方法)
2、把 *类放在函数形参中。
3、把 *变量放在函数体中,赋值号左边。(真的改变传的变量)

例如:lotus源码中:\extern\sector-storage\manager.go

func (m *Manager) readPiece(sink io.Writer, sector storage.SectorRef, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, rok *bool) func(ctx context.Context, w Worker) error {
	return func(ctx context.Context, w Worker) error {
		r, err := m.waitSimpleCall(ctx)(w.ReadPiece(ctx, sink, sector, offset, size))
		if err != nil {
			return err
		}
		if r != nil {
			*rok = r.(bool)
		}
		return nil
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值