Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

    • Golang环境

    • 语法

    • 数据类型与运算符

    • 分支语句

    • 循环语句

    • 数组

    • 切片

    • Map

    • String

    • 函数

    • 包的管理

    • 指针

    • 结构体

    • Go语言中的OOP

    • 方法和接口

      • 方法和接口
      • 方法
        • 接口
        • 接口嵌套
        • 接口断言
        • type关键字
      • 错误处理

    • Go进阶

    • Go框架

    • Golang辅助

    • Golang
    • 基础
    • 方法和接口
    Bruce
    2022-10-27
    目录

    方法

    # 方法

    # 1.1 什么是方法

    • Go语言中同时有函数和方法.一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针.所有给定类型的方法属于该类型的方法集
    • 方法只是一个函数,它带有一个特殊的接收器类型,它是在func关键字和方法名之间编写的.接收器可以是struct类型或非struct类型.接收方可以在方法内部访问.
    • 方法能给用户自定义的类型添加新的行为.**它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法.**接收者可以是值接收者,也可以是指针接收者.
    • 在调用方法的时候,值类型既可调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法.
    • 也就是说,不管方法的接收者时什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型.

    # 1.2 方法的语法

    • 定义方法的语法
    func (t Type) methodName(parameter list)(return list) {
      
    }
    func funcName(parameter list)(return list){
        
    }
    
    1
    2
    3
    4
    5
    6

    实例代码:

    package main
    
    import (  
        "fmt"
    )
    
    type Employee struct {  
        name     string
        salary   int
        currency string
    }
    
    /*
     displaySalary() method has Employee as the receiver type
    */
    func (e Employee) displaySalary() {  
        fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
    }
    
    func main() {  
        emp1 := Employee {
            name:     "Sam Adolf",
            salary:   5000,
            currency: "$",
        }
        emp1.displaySalary() //Calling displaySalary() method of Employee type
    }
    
    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
    # 可以定义相同的方法名

    示例代码:

    package main
    
    import (
    	"fmt"
    	"math"
    )
    
    type Rectangle struct {
    	width, height float64
    }
    type Circle struct {
    	radius float64
    }
    
    
    func (r Rectangle) area() float64 {
    	return r.width * r.height
    }
    //该 method 属于 Circle 类型对象中的方法
    func (c Circle) area() float64 {
    	return c.radius * c.radius * math.Pi
    }
    func main() {
    	r1 := Rectangle{12, 2}
    	r2 := Rectangle{9, 4}
    	c1 := Circle{10}
    	c2 := Circle{25}
    	fmt.Println("Area of r1 is: ", r1.area())
    	fmt.Println("Area of r2 is: ", r2.area())
    	fmt.Println("Area of c1 is: ", c1.area())
    	fmt.Println("Area of c2 is: ", c2.area())
    }
    
    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

    运行结果

    Area of r1 is:  24
    Area of r2 is:  36
    Area of c1 is:  314.1592653589793
    Area of c2 is:  1963.4954084936207
    
    1
    2
    3
    4
    • 虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样
    • method里面可以访问接收者的字段
    • 调用method通过.访问,就像struct里面访问字段一样

    # 1.3 方法和函数

    • 既然已经有了函数,为什么还要使用方法?

    示例代码:

    package main
    
    import (  
        "fmt"
    )
    
    type Employee struct {  
        name     string
        salary   int
        currency string
    }
    
    /*
     displaySalary() method converted to function with Employee as parameter
    */
    func displaySalary(e Employee) {  
        fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
    }
    
    func main() {  
        emp1 := Employee{
            name:     "Sam Adolf",
            salary:   5000,
            currency: "$",
        }
        displaySalary(emp1)
    }
    
    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

    在上面的程序中,displaySalary方法被转换为一个函数,而Employee struct作为参数传递给它.这个程序也产生了相同的输出:Salary of Sam Adolf is $5000.

    为什么可以用函数来写相同的程序呢?有以下几个原因:

    • 1.Go不是一种纯粹面向对象的编程语言,它不支持类.因此,类型的方法是一种实现类似于类的行为的方法.
    • 2.相同名称的方法可以在不同的类型上定义,而具有相同名称的函数是不允许的.假设有一个正方形和圆形的结构.可以在正方形和圆形上定义一个名为Area的方法.这是在下面的程序中完成的.

    # 1.4 变量作用域

    作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围.

    Go语言中变量可以在三个地方声明:

    • 函数内定义的变量称为局部变量
    • 函数外定义的变量称为全局变量
    • 函数定义中的变量称为形式参数
    # 局部变量
    • 在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量.
    # 全局变量
    • 在函数体外声明的变量称之为全局变量,首字母大写全局变量可以在整个包甚至外部包(被导出后)使用.
    package main
    
    import "fmt"
    
    /* 声明全局变量 */
    var g int
    
    func main() {
    
       /* 声明局部变量 */
       var a, b int
    
       /* 初始化参数 */
       a = 10
       b = 20
       g = a + b
    
       fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    结果

    结果: a = 10, b = 20 and g = 30
    
    1
    # 形式参数
    • 形式参数会作为函数的局部变量来使用
    # 指针作为接收者
    • 若不是以指针作为接收者,实际只是获取了一个copy,而不能真正改变接收者的中的数据
    func (b *Box) SetColor(c Color) {
    	b.color = c
    }
    
    1
    2
    3

    示例代码

    package main
    
    import (
    	"fmt"
    )
    
    type Rectangle struct {
    	width, height int
    }
    
    func (r *Rectangle) setVal() {
    	r.height = 20
    }
    
    func main() {
    	p := Rectangle{1, 2}
    	s := p
    	p.setVal()
    	fmt.Println(p.height, s.height)
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    结果

    20 2
    
    1

    如果没有那个*,则值就是2 2

    # 1.5 method继承

    • method是可以继承的,如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method
    package main
    
    import "fmt"
    
    type Human struct {
    	name  string
    	age   int
    	phone string
    }
    type Student struct {
    	Human  //匿名字段
    	school string
    }
    type Employee struct {
    	Human   //匿名字段
    	company string
    }
    
    func (h *Human) SayHi() {
    	fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
    }
    func main() {
    	mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    	sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
    	mark.SayHi()
    	sam.SayHi()
    }
    
    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

    运行结果:

    Hi, I am Mark you can call me on 222-222-YYYY
    Hi, I am Sam you can call me on 111-888-XXXX
    
    1
    2

    image-20221023171843838

    package main
    
    import "fmt"
    
    func main() {
    	/*
    		OOP中的继承性:
    			如果两个类(class)存在继承关系,其中一个是子类,另一个作为父类,那么:
    				1.子类可以直接访问父类的属性和方法
    				2.子类可以新增自己的属性和方法
    				3.子类可以重写父类的方法(orverride,就是将父类已有的方法,重新实现)
    
    		Go语言的结构体嵌套:
    			1.模拟继承性: is - a
    				type A struct {
    					field
    				}
    				type B struct {
    					A //匿名字段
    				}
    
    			2.模拟聚合关系: has - a
    				type C struct {
    					field
    				}
    				type D struct {
    					c C //聚合关系
    				}
    	*/
    
    	//1.创建Person类型
    	p1 := Person{name: "王二狗", age: 30}
    	fmt.Println(p1.name, p1.age) //父类对象,访问父类的字段属性
    	p1.eat()                     //父类对象,访问父类的方法
    
    	//2.创建Student类型
    	s1 := Student{Person{"Ruby", 18}, "Golang学习"}
    	fmt.Println(s1.name)   //s2.Person.name
    	fmt.Println(s1.age)    //子类对象,可以直接访问父类的字段(其实就是提升字段)
    	fmt.Println(s1.school) //子类对象,访问自己新增的字段属性
    
    	s1.eat()   //子类对象,访问父类的方法
    	s1.study() //子类对象,访问自己新增的方法
    	s1.eat()   //如果存在方法的重写,子类对象访问重写的方法
    }
    
    //1.定义一个"父类"
    type Person struct {
    	name string
    	age  int
    }
    
    //2.定义一个"子类"
    type Student struct {
    	Person //结构体嵌套,模拟继承性
    	school string
    }
    
    //3.方法
    func (p Person) eat() {
    	fmt.Println("父类的方法,吃海鲜......")
    }
    
    //新增方法
    func (s Student) study() {
    	fmt.Println("子类新增方法,学生们学习...")
    }
    
    func (s Student) eat() {
    	fmt.Println("子类重写的方法: 吃香喝辣...")
    }
    
    
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    打印输出

    $ go run 38.struct/demo01-struct.go
    王二狗 30
    父类的方法,吃海鲜......
    Ruby
    18
    Golang学习
    子类重写的方法: 吃香喝辣...
    子类新增方法,学生们学习...
    子类重写的方法: 吃香喝辣...
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 1.6 method重写

    package main
    
    import "fmt"
    
    type Human struct {
    	name  string
    	age   int
    	phone string
    }
    type Student struct {
    	Human  //匿名字段
    	school string
    }
    type Employee struct {
    	Human   //匿名字段
    	company string
    }
    
    //Human定义method
    func (h *Human) SayHi() {
    	fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
    }
    
    //Employee的method重写Human的method
    func (e *Employee) SayHi() {
    	fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
    		e.company, e.phone) //Yes you can split into 2 lines here.
    }
    func main() {
    	mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    	sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
    	mark.SayHi()
    	sam.SayHi()
    }
    
    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
    33
    34

    运行结果:

    Hi, I am Mark you can call me on 222-222-YYYY
    Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX
    
    1
    2
    • 方法是可以继承和重写的
    • 存在继承关系时,按照就近原则,进行调用
    上次更新: 2024/04/09, 16:48:42
    方法和接口
    接口

    ← 方法和接口 接口→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式