文章目录
一、指针
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}
}