• 面向对象之方法2


    方法的调用和传参机制原理:(重要!)

    说明:方法的调用和传参机制和函数基本一样,不一样的地方是方法调用时,会将调用方法的变量,当做实参也传递给方法。下面我们举例说明:

    案例1:画出前面getSum 方法的执行过程+说明

    说明:

    1)在通过一个变量去调用方法时,其调用机制和函数一样。
    2)不一样的地方,变量调用方法时,该变量本身也会作为一个参数传递到方法里面去。(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地址拷贝)


    案例2:请编写一个程序,要求如下:

    1)声明一个结构体Cirle,字段为radius

    2)声明一个方法 area 和 Cirle 绑定,可以返回面积。

    3)提示:画出area执行过程+说明

    方法使用的深度剖析:

    方法的声明(定义)

    func (recevier type) methodName (参数列表) (返回值列表) {
      方法体
      return 返回值
    }

    1)参数列表:表示方法输入

    2)recevier type:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型

    3)recevier type:type可以是结构体,也可以是其它的自定义类型

    4)recevier type:就是type类型的一个变量(实例),比如:Person结构体 的一个变量(实例)

    5)返回值列表:表示返回的值,可以多个

    6)方法主图:表示为了实现某一功能代码块

    7)return 语句不是必须的


    方法注意事项和细节讨论:

      1)结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式

      2)如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理

    案例演示:

    type Circle struct {
      radius float64
    }

    //为了提高效率,通常我们方法和结构体的指针类型绑定
    func (c *Circle) area2() float64 {
      //因为c是指针,因此我们标准的访问其字段的方式是 (*c).radius
      //return 3.14 * (*c).radius * (*c).radius
      //(*c).radius 等价 c.radius
      c.radius = 10.0
      return 3.14 * c.radius * c.radius
    }

    func main() {

      var c Circle
      c.radius = 7.0
      //res2 := (&c).area2()
      res2 := c.area2()
      //编译器底层做了优化 (&c).area2() 等价 c.ares2()
      //因为编译器会自动给加上&c
      fmt.Println("面积是=", res2)
      fmt.Println("c.radius=", c.radius) //10
    }

    3)Golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32等都可以有方法

    案例:
    package main
    import (
      "fmt"
    )

    type integer int

    func (i integer) print() {
      fmt.Println("i=", i)
    }

    //编写一个方法,可以改变i的值
    func (i *integer) change() {
      *i = *i + 1
    }

    func main() {
      var i integer = 10
      i.print()
      i.change()
      fmt.Println("i=",i)
    }


    4)方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。

    5)如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出

    案例:

    type Student struct {
      Name string
      Age int
    }

    func (stu *Student) String() string {
      str := fmt.Sprintf("Name=[%v] Age=[%v]", stu.Name, stu.Age)
      return str
    }

    func main() {

      stu := Student{
      Name : "tom",
      Age : 20,
      }
      //如果你实现了 *Student 类型的 String方法,就会自动调用
      fmt.Println(&stu)
    }

    方法和函数的区别:

    1)调用方式不一样

      函数的调用方式: 函数名(实参列表)
      方法的调用方式: 变量.方法名(实参列表)

    2)对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递

    案例:
    type Person struct {
      Name string
    }

    func test01(p Person) {
      fmt.Println(p.Name)
    }

    func test02(p *Person) {
      fmt.Println(p.Name)
    }

    func main() {

      p := Person{"tom"}
      test01(p) //因为是值拷贝,所以不能传入地址 test01(*p)这么写会报错的
      test02(&p) //因为是地址拷贝,所以不能直接值拷贝,test02(p)这么写也会报错的。
    }

    3)对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。

    案例:
    type Person struct {
      Name string
    }

    func (p Person) test03() { //虽然main函数里是以传入地址的方式,但是在p接收的时候还是值拷贝的,所以下面的jack该的只是方法里的值,而main函数里的值是不会更改的。
      p.Name = "jack"
      fmt.Println("test03() =", p.Name) //jack
    }

    func (p *Person) test04() { //因为是指针类型,所以接收的会是一个指针地址,所以在方法里更改name的值,也就是更改main函数里的值。
      p.Name = "mary"
      fmt.Println("test04() =", p.Name) //mary
    }


    func main() {

      p := Person{"tom"}
      p.test03()
      fmt.Println("main() p.name=", p.Name) //tom

      (&p).test03() //从形式上是传入地址,但本质仍然是值拷贝
      fmt.Println("main p.name=", p.Name) //tom

      (&p).test04()
      fmt.Println("main() p.name=", p.Name) //mary
      p.test04() //等价 (&p).test04() 从形式上是传入值类型,但本质仍然是地址拷贝
    }


    总结:

      1)不管调用形式如何,真正决定是值拷贝还是地址拷贝,主要是看这个方法是和哪个类型绑定的。

      2)如果是和值类型绑定的,比如 (p Person),则是值拷贝,如果是和指针类型绑定的,比如(p *Person),则是地址拷贝。

  • 相关阅读:
    百度地图之自动提示--autoComplete
    h5之scrollIntoView控制页面元素滚动
    angular之interceptors拦截器
    angular之$broadcast、$emit、$on传值
    前端基础入门(一)-HTML-HTML基础
    改进自定义博客
    自定义博客主题
    使用JavaScript策略模式校验表单
    【经典面试题】圣杯布局以及双飞翼布局原理
    [JavaScript设计模式]惰性单例模式
  • 原文地址:https://www.cnblogs.com/green-frog-2019/p/11408154.html
Copyright © 2020-2023  润新知