zoukankan      html  css  js  c++  java
  • 6.1Go方法

    第六章 Go方法

    第三章中讲解了struct,面向对象编程OOP已经是一个编程范式了,Go语言同样支持OOP开发。

    一个对象就是一个变量,在这个对象中包含了一些方法,一个方法是一个和特殊类型关联的函数。

    函数function,是一段具有独立功能的代码,可以反复被调用

    方法method,是一个类的行为功能,只有该类的对象才可以调用

    一个Person结构体,除了有基本的字段(姓名、年纪、性别…等等),Person结构体还应该有一些行为动作,如(吃饭、说话、跑步、学习等…),这些事需要定义方法去完成。

    Go的方法是作用在指定的数据类型上的,与数据类型绑定,自定义类型都可以有方法,不仅仅是struct。隐式的将struct实例作为第一实参(receiver)。

    可以为当前包内的任意类型定义方法。

    package main
    type X int
    func (x *X)inc(){                //方法前的变量参数x称作 receiver,作用类似python的self
      *x++
    }
    func main(){
        var x X 
      x.inc()
      println(x)
    }
    

    1.1. 方法的声明和调用

    package main
    
    import "fmt"
    
    //定义一个结构体数据类型
    type Person struct {
        Username string
        Age      int
        Sex      string
    }
    
    //表示给Person结构体,绑定添加test方法
    func (p Person) test() {
        fmt.Println("通过p变量,取出结构体类型中的Username值是:", p.Username)
    }
    
    func main() {
        p1 := &Person{
            "狗子",
            18,
            "男",
        }
        p1.test()
    }
    

    总结method

    1.test方法和Person结构体类型绑定
    2.test方法只能通过Person结构体的实例调用
    

    语法

    一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。
    
    所有给定类型的方法属于该类型的方法集。
    
    方法定义:
    
    func (recevier type) methodName(参数列表)(返回值列表){}
    
    参数和返回值可以省略
    package main
    
    type Test struct{}
    
    // 无参数、无返回值
    func (t Test) method0() {
    
    }
    
    // 单参数、无返回值
    func (t Test) method1(i int) {
    
    }
    
    // 多参数、无返回值
    func (t Test) method2(x, y int) {
    
    }
    
    // 无参数、单返回值
    func (t Test) method3() (i int) {
        return
    }
    
    // 多参数、多返回值
    func (t Test) method4(x, y int) (z int, err error) {
        return
    }
    
    // 无参数、无返回值
    func (t *Test) method5() {
    
    }
    
    // 单参数、无返回值
    func (t *Test) method6(i int) {
    
    }
    
    // 多参数、无返回值
    func (t *Test) method7(x, y int) {
    
    }
    
    // 无参数、单返回值
    func (t *Test) method8() (i int) {
        return
    }
    
    // 多参数、多返回值
    func (t *Test) method9(x, y int) (z int, err error) {
        return
    }
    
    func main() {}
    

    自定义数据类型绑定方法

    package main
    
    import (
        "fmt"
    )
    
    type Integer int
    
    func (i Integer) Print() {
        fmt.Println("i的值:", i)
    }
    
    func main() {
        var a Integer
        a = 1000
        a.Print()
    
        var b int = 200
        a = Integer(b)
        a.Print()
    }
    

    1.2. 方法实战

    package main
    
    import "fmt"
    
    //定义一个结构体数据类型
    type Person struct {
        Username string
        Age      int
        Sex      string
    }
    
    //此时这个(p Person)就是一个接受者
    //Person结构体,人是可以说话的,添加speak方法
    func (p Person) speak() {
        fmt.Printf("大声的喊出了自己的名字:%v
    ", p.Username)
    }
    
    //人还可以蹦跳
    func (p Person) jump() {
        fmt.Printf("%v:跳起来一拳打在了姚明的膝盖上
    ", p.Username)
    }
    
    //人还可以进行算数
    //方法的参数列表与返回值列表,与函数一致
    func (p Person) getSum(n1, n2 int) int {
        sum := n1 + n2
        fmt.Printf("%v:飞快的计算出%d+%d的结果是%d
    ", p.Username, n1, n2, sum)
        return sum
    }
    func main() {
        p1 := &Person{
            "李二狗",
            18,
            "男",
        }
        p1.speak()
        p1.jump()
        res := p1.getSum(1, 2)
        fmt.Printf("p1.getSum方法返回值是%d
    ", res)
    }
    

    1.3. 方法使用细节

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

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

    3)当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。

    package main
    
    import "fmt"
    
    type People struct {
        Name    string
        Country string
    }
    
    //此方法进行了值拷贝
    func (p People) Print() {
        fmt.Printf("我是谁:name=%s country=%s
    ", p.Name, p.Country)
    }
    
    //此方法进行了值拷贝,不会对p1进行修改
    func (p People) Set(name string, country string) {
        p.Name = name
        p.Country = country
    }
    
    //接收一个指针变量,可以修改原值
    func (p *People) SetV2(name string, country string) {
        p.Country = country
        p.Name = name
    }
    
    func main() {
        var p1 People = People{
            Name:    "二狗子",
            Country: "沙河",
        }
    
        p1.Print()
        //此处修改无效,并没有修改p1的原地址
        p1.Set("二狗腿子", "日本")
        p1.Print()
    
        //两者效果一样,是被编译器进行了优化
        //(&p1).SetV2("people02", "english")
        p1.SetV2("狗官", "日本")
        p1.Print()
    }
    

    1.4. 方法和函数的区别

    1.调用方式区别

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

    2.对于普通函数,接受者为值类型时,不能将指针类型数据直接传递,传递时编译器就提示报错

    package main
    
    import "fmt"
    
    func test(n1 int) int {
        n1 = n1 + 10
        return n1
    }
    
    func test2(n1 *int) int {
        *n1 = *n1 + 10
        return *n1
    }
    
    func main() {
        var num = 10
        //test函数接收的num有一个值拷贝的过程
        res := test(num)
        fmt.Println("值传递函数test结果:", res)
        fmt.Println("值传递函数test修改num的结果:", num)
    
        //test2函数接收num变量的地址,因此修改的也是num的值
        res1 := test2(&num)
        fmt.Println("指针传递函数test2结果:", res1)
        fmt.Println("值传递函数test2修改num的结果:", num)
    }
    

    3.对于方法(如struct的方法),接受者是值类型时,可以直接用指针类型变量调用方法,反之亦然。

    package main
    
    import "fmt"
    
    type Person struct {
        Name string
    }
    
    func (p Person) test01() {
        p.Name = "码云"
        fmt.Printf("test01修改了name值:%v
    ", p.Name)
    }
    
    func (p *Person) test02() {
        p.Name = "麻花藤"
        fmt.Printf("test02修改了name值:%v
    ", p.Name)
    }
    
    func main() {
        var p1 Person = Person{
            "刘强东",
        }
        fmt.Println("p1默认值:", p1)
    
        //调用test01,由于值拷贝,并没有修改默认p1的Name值
        //(&p1).test01() 即使传入地址,仍然进行了值拷贝
        p1.test01()
        fmt.Printf("此时main程序调用p1.test01,此时p1.Name值:%v
    ", p1.Name)
    
        //传入地址
        //可以简写p1.test02(),修改的是p1.Name原本内存地址
        (&p1).test02()
        fmt.Printf("main程序调用p1.test02,此时p1.Name值%v
    ", p1.Name)
    }
  • 相关阅读:
    作业2 求题目中的数
    2013 C#单元测试
    实现项目WC
    带括号多项式版四则运算
    20道简单加减法随机生成程序扩展版体会
    20道简单加减法随机生成程序
    Jeesite 集成微信支付接口
    第一节:JAVA 语言的学习目标
    vector(未完)
    关于phpstorm端口63342的修改经历
  • 原文地址:https://www.cnblogs.com/open-yang/p/11256874.html
Copyright © 2011-2022 走看看