Go -- 方法、和指针

一、指针

1.1、 什么是指针

  • 一个指针变量指向了一个值的内存地址。

  • 类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var_name *var-type

var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:

var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

1.2、如何使用指针

指针使用流程:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。

在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

package main

import "fmt"

func main() {
	var a int = 20
	var ip *int
	ip = &a
	fmt.Println(ip)

	fmt.Printf("a 变量的地址是: %x\n", &a)
	/* 指针变量的存储地址 */
	fmt.Printf("ip 变量储存的指针地址: %x\n", ip)
	/* 使用指针访问值 */
	fmt.Printf("*ip 变量的值: %d\n", *ip)
}

二、方法是什么?

  • Go语言中的方法其实就是一个特殊的函数,只不过这个函数是和某种属性类型绑定在一起的而已
  • Go语言中的方法 一般用于将函数和结构体绑定一起,体绑定在一起 , 让结构体除了能够保存数据外还能具备某些行为

2.1、方法的定义

• 只能为当前包内命名类型定义方法。
• 参数 receiver 可任意命名。如方法中未曾使用 ,可省略参数名。
• 参数 receiver 类型可以是 T 或 *T。基类型 T 不能是接口或指针。 
• 不支持方法重载,receiver 只是参数签名的组成部分。
• 可用实例 value 或 pointer 调用全部方法,编译器自动转换。

一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

2.2、将函数和数据类型绑定的格式

  • 只需要在函数名称前面加上(接收者 数据类型),即可将函数和某种数据类型绑定在一起
func (接收者 数据类型)方法名称(形参列表)(返回值列表){
	方法体
}
    func (recevier type) methodName(参数列表)(返回值列表){}
    参数和返回值可以省略

方法在定义的时候,会在func和方法名之间增加一个参数,这个参数就是接收者,这样我们定义的这个方法就和接收者绑定在了一起,称之为这个接收者的方法。

2.3 使用方法绑定对象实例

  • 方法的声明和函数类似,他们的区别是:方法在定义的时候,会在func和方法名之间增加一个参数,这个参数就是接收者,这样我们定义的这个方法就和接收者绑定在了一起,称之为这个接收者的方法。

type:

type MedOne struct{ Name string }  //外部调用需要大写开头

func (med MedOne) MedOne() string {
	return "this medOne'name is " + med.Name
}

main 中调用方法

func main() {
	med := medOne.MedOne{"老王"}
	fmt.Println(med.MedOne())
}
  • 例子二:
type Person struct {
	Name string
	age  int
}

func (p Person) PersonMed() string {
	return "This is person's name" + p.Name
}

  • 留意例子中,func和方法名之间增加的参数(p person),这个就是接收者。现在我们说,类型person有了一个String方法,现在我们看下如何使用它。
func main() {
	p := medOne.Person{Name: "老张头"}
	fmt.Println(p.PersonMed())
}

2.4 方法绑定指针对象

  • 值接收者和指针接收者。我们上面的例子中,就是使用值类型接收者的示例

  • 使用值类型接收者定义的方法,在调用的时候,使用的其实是值接收者的一个副本,所以对该值的任何操作,不会影响原来的类型变量。

package main

import "fmt"

func main() {
	fmt.Println("hello")
	p := Person{"老张"}
	p.modify() //调用修改name的方法,值接收者,修改无效
	fmt.Println(p.GetName())  // this is person's name老张
}

type Person struct {
	name string
}

func (p Person) GetName() string {
	return "this is person's name" + p.name
}

// 修改Person类的name值
func (p Person) modify() {
	p.name = "老王"
}
  • 以上的例子,打印出来的值还是老张,对其进行的修改无效。如果我们使用一个指针作为接收者,那么就会其作用了,因为指针接收者传递的是一个指向原值指针的副本,指针的副本,指向的还是原来类型的值,所以修改时,同时也会影响原来类型变量的值。
package main

import "fmt"

func main() {
	fmt.Println("hello")
	p := person{"老张头"}
	p.modify()               // 指针接收者,修改有效
	fmt.Println(p.GetName()) // this is person's name老王头
}

type person struct {
	name string
}

func (p person) GetName() string {
	return "this is person's name" + p.name
}

// 修改person类的name值
func (p *person) modify() {
	p.name = "老王头"
}

只需要改动一下,变成指针的接收者,就可以完成了修改

  • 在上面的例子中,有没有发现,我们在调用指针接收者方法的时候,使用的也是一个值的变量,并不是一个指针,如果我们使用下面的也是可以的。
p:=person{name:"张三"}
(&p).modify() //指针接收者,修改有效

  • 这样也是可以的。如果我们没有这么强制使用指针进行调用,Go的编译器自动会帮我们取指针,以满足接收者的要求。
    同样的,如果是一个值接收者的方法,使用指针也是可以调用的,Go编译器自动会解引用,以满足接收者的要求,比如例子中定义的String()方法,也可以这么调用:
p:=person{name:"张三"}
fmt.Println((&p).GetName())

2.5、址传递的几种调用方式

package main

import "fmt"

type personFridayOne struct {
	name string
	age  int
}

// 接收者是一个变量
func (o personFridayOne) setName(name string) {
	o.name = name
}

// 接收者是一个指针
func (o *personFridayOne) setAge(age int) {
	o.age = age
}
func main() {
	per := personFridayOne{"老王头", 20}

	//方式一: 先拿到指针,然后再通过指针调用
	p := &per
	(*p).setAge(30)
	fmt.Println(per) //{老王头 30}

	//方式二:直接利用变量调用, 底层会自动获取变量地址传递给接收者
	per.setAge(40)
	fmt.Println(per) // {老王头 40}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lovely_red_scarf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值