• Go -- 方法、和指针


    一、指针

    1.1、 什么是指针

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

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

    var var_name *var-type
    
    • 1

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

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

    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)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    二、方法是什么?

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

    2.1、方法的定义

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

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

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

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

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

    2.3 使用方法绑定对象实例

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

    type:

    type MedOne struct{ Name string }  //外部调用需要大写开头
    
    func (med MedOne) MedOne() string {
    	return "this medOne'name is " + med.Name
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    main 中调用方法

    func main() {
    	med := medOne.MedOne{"老王"}
    	fmt.Println(med.MedOne())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 例子二:
    type Person struct {
    	Name string
    	age  int
    }
    
    func (p Person) PersonMed() string {
    	return "This is person's name" + p.Name
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 留意例子中,func和方法名之间增加的参数(p person),这个就是接收者。现在我们说,类型person有了一个String方法,现在我们看下如何使用它。
    func main() {
    	p := medOne.Person{Name: "老张头"}
    	fmt.Println(p.PersonMed())
    }
    
    • 1
    • 2
    • 3
    • 4

    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 = "老王"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 以上的例子,打印出来的值还是老张,对其进行的修改无效。如果我们使用一个指针作为接收者,那么就会其作用了,因为指针接收者传递的是一个指向原值指针的副本,指针的副本,指向的还是原来类型的值,所以修改时,同时也会影响原来类型变量的值。
    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 = "老王头"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    • 在上面的例子中,有没有发现,我们在调用指针接收者方法的时候,使用的也是一个值的变量,并不是一个指针,如果我们使用下面的也是可以的。
    p:=person{name:"张三"}
    (&p).modify() //指针接收者,修改有效
    
    
    • 1
    • 2
    • 3
    • 这样也是可以的。如果我们没有这么强制使用指针进行调用,Go的编译器自动会帮我们取指针,以满足接收者的要求。
      同样的,如果是一个值接收者的方法,使用指针也是可以调用的,Go编译器自动会解引用,以满足接收者的要求,比如例子中定义的String()方法,也可以这么调用:
    p:=person{name:"张三"}
    fmt.Println((&p).GetName())
    
    • 1
    • 2

    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}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    初识exception
    用python实现堆排序(附内置函数)
    docker系列(1) - docker环境篇
    探索网络世界:常见应用程序详解与实战演练
    php 5.3开始使用mysqlnd作为的默认mysql访问驱动
    Linux进程理解(上)
    【学习笔记】windows 下的 shared memory(共享内存)
    GRS全球回收标准-未来趋势
    C陷阱与缺陷 第7章 可移植性缺陷 7.2 标识符名称的限制
    MySQL全库只读,不推荐使用set global readonly=true
  • 原文地址:https://blog.csdn.net/Lovely_red_scarf/article/details/127538375