zoukankan      html  css  js  c++  java
  • Golang

    Golang - 面对"对象"

    1. 简介

    • go语言对于面向对象的设计非常简洁而优雅
    • 没有封装、继承、多态这些概念,但同样通过别的方式实现这些特性
    • 封装:通过方法实现
    • 继承:通过匿名字段实现
    • 多态:通过接口实现

    2. 匿名字段

    go支持只提供类型而不写字段名的方式,也就是匿名字段,也称为嵌入字段

    //package 声明开头表示代码所属包
    package main
    
    import "fmt"
    
    //定义人的结构体
    type Person struct {
    	name string
    	sex  string
    	age  int
    }
    
    //学生
    type Student struct {
    	//匿名字段
    	//默认Student包含了Person所有字段
    	Person
    	id   int
    	addr string
    }
    
    func main() {
    	
    	s2 := Student{Person:Person{"约汉","female",10},id:2}
    	fmt.Println(s2)
    }
    
    //{{约汉 female 10} 2 }
    

    同名字段的情况

    //package 声明开头表示代码所属包
    package main
    
    import "fmt"
    
    //定义人的结构体
    type Person struct {
    	name string
    	sex  string
    	age  int
    }
    
    //学生
    type Student struct {
    	//匿名字段
    	//默认Student包含了Person所有字段
    	Person
    	id   int
    	addr string
    	//同名字段
    	name string
    }
    
    func main() {
    	var s Student
    	//就近赋值
    	s.name = "约汉"
    	fmt.Println(s)
    	//若给外面赋值
    	s.Person.name = "接客"
    	fmt.Println(s)
    }
    
    //{{  0} 0  约汉}
    //{{接客  0} 0  约汉}
    

    所有的内置类型和自定义类型都是可以作为匿名字段去使用

    package main
    
    import "fmt"
    
    //定义人的结构体
    type Person struct {
       name string
       sex  string
       age  int
    }
    
    //自定义类型
    type mystr string
    
    //学生
    type Student struct {
       //匿名字段
       //默认Student包含了Person所有字段
       Person
       //内置
       int
       mystr
    }
    
    func main() {
       //初始化
       s1 := Student{Person{"约汉","male",18},1,"bj"}
       fmt.Println(s1)
       fmt.Println(s1.name)
    }
    

    指针类型匿名字段

    //package 声明开头表示代码所属包
    package main
    
    import "fmt"
    
    //定义人的结构体
    type Person struct {
    	name string
    	sex  string
    	age  int
    }
    
    //学生
    type Student struct {
    	//匿名字段
    	//默认Student包含了Person所有字段
    	*Person
    	//内置
    	id int
    	addr string
    }
    
    func main() {
    	s1 := Student{&Person{"约汉","male",18},1,"bj"}
    	fmt.Println(s1)
    	fmt.Println(s1.name)
    }
    
    //{0xc0420661e0 1 bj}
    //约汉
    

    3. 方法

    4. 包和封装

    5. 接口

    • 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数
    • 这种带有接收者的函数,我们称为方法,本质上,一个方法则是一个和特殊类型关联的函数
    • 方法的语法如下
    • func (接收参数名 接收类型) 方法名(参数列表)(返回值)
    • 可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
    • 接收类型可以是指针或非指针类型
    • 为类型添加方法(为基础类型添加方法和为结构体类型添加方法)
      • 基础类型

          //package 声明开头表示代码所属包
          package main
          
          import "fmt"
          
          //任务:定义方法实现2个数相加
          
          type MyInt int
          
          //传统定义方式,面向过程
          func Add(a, b MyInt) MyInt {
          	return a + b
          }
          
          //面向对象
          func (a MyInt) Add(b MyInt) MyInt {
          	return a + b
          }
          
          func main() {
          	var a MyInt = 1
          	var b MyInt = 1
          	fmt.Println("Add(a,b)=", Add(a, b))
          	//调用面向对象的方法
          	fmt.Println("a.Add(b)=",a.Add(b))
          }
          
          
          //Add(a,b)= 2
          //a.Add(b)= 2
        
      • 结构体类型

          //package 声明开头表示代码所属包
          package main
          
          import "fmt"
          
          type Person struct {
          	name string
          	sex  string
          	age  int
          }
          
          //为Person添加方法
          func (p Person) PrintInfo() {
          	fmt.Println(p.name, p.sex, p.age)
          }
          
          func main() {
          	p := Person{"接客", "male", 18}
          	p.PrintInfo()
          }
        
      • 值语义和引用语义

          //package 声明开头表示代码所属包
          package main
          
          import "fmt"
          
          type Person struct {
          	name string
          	sex  string
          	age  int
          }
          
          //设置指针作为接收者的方法,引用语义
          func (p *Person) SetInfoPointer() {
          	(*p).name = "接客"
          	p.sex = "female"
          	p.age = 22
          }
          
          //值作为接收者,值语义
          func (p Person) SetInfoValue() {
          	p.name = "约汉"
          	p.sex = "male"
          	p.age = 20
          }
          
          func main() {
          	//指针作为接收者的效果
          	p1 := Person{"撸死", "male", 19}
          	fmt.Println("函数调用前=", p1)
          	(&p1).SetInfoPointer()
          	fmt.Println("函数调用后=", p1)
          	fmt.Println("================寂寞的分割线=================")
          
          	//值作为接收者的效果
          	p2 := Person{"约汉", "male", 18}
          	fmt.Println("函数调用前=", p2)
          	p2.SetInfoValue()
          	fmt.Println("函数调用后=", p2)
          }
          
          
          //函数调用前= {撸死 male 19}
          //函数调用后= {接客 female 22}
          //================寂寞的分割线=================
          //函数调用前= {约汉 male 18}
          //函数调用后= {约汉 male 18}
        
      • 方法的继承

          package main
          
          import "fmt"
          
          type Person struct {
             name string
             sex  string
             age  int
          }
          
          //为Person定义方法
          func (p *Person) PrintInfo()  {
             fmt.Printf("%s,%s,%d
        ",p.name,p.sex,p.age)
          
          }
          
          type Student struct {
             Person
             id int
             addr string
          }
          
          func main()  {
             p :=Person{"接客","male",18}
             p.PrintInfo()
             //学生也去调,方法继承
             s := Student{Person{"接客","male",18},2,"bj"}
             s.PrintInfo()
          }
        
      • 方法的重写

          package main
          
          import "fmt"
          
          type Person struct {
             name string
             sex  string
             age  int
          }
          
          //为Person定义方法
          func (p *Person) PrintInfo() {
             fmt.Printf("%s,%s,%d
        ", p.name, p.sex, p.age)
          }
          
          type Student struct {
             Person
             id   int
             addr string
          }
          
          //Student定义方法,实际上就相当于方法重写
          func (s *Student) PrintInfo() {
             fmt.Printf("Student:%s,%s,%d
        ", s.name, s.sex, s.age)
          }
          
          func main() {
             p := Person{"接客", "male", 18}
             p.PrintInfo()
             //学生也去调,方法继承
             s := Student{Person{"接客", "male", 18}, 2, "bj"}
             s.PrintInfo()
             //显式调用
             s.Person.PrintInfo()
          }
        
      • 方法值和方法表达式

          package main
          
          import "fmt"
          
          type Person struct {
             name string
             sex  string
             age  int
          }
          
          func (p *Person) PrintInfoPointer() {
             //%p是地址,%v是值
             fmt.Printf("%p,%v
        ", p, p)
          }
          
          func main() {
             p := Person{"接客", "male", 18}
             //传统的调用方法的方式
             p.PrintInfoPointer()
             //使用go方法值特性调用
             pFunc1 := p.PrintInfoPointer
             pFunc1()
             //使用go方法表达式调用
             pFunc2 := (*Person).PrintInfoPointer
             pFunc2(&p)
          }
        

    练习:创建属性的getter和setter方法并进行调用

    	package main
    	
    	import "fmt"
    	
    	type Dog struct {
    	   name string
    	   //1公  0母
    	   sex int
    	}
    	
    	//封装dog的方法
    	//setter
    	func (d *Dog) SetName(name string) {
    	   d.name = name
    	}
    	
    	//getter
    	func (d *Dog) GetName() string {
    	   return d.name
    	}
    	
    	//咬人
    	func (d *Dog) bite() {
    	   fmt.Printf("让本汪%s 来给你上课...", d.name)
    	}
    	
    	func main() {
    	   d := Dog{"二哈", 1}
    	   d.bite()
    	}
    

    4. 包和封装

    • 方法首字母大写:public
    • 方法首字母小写:private
    • 为结构体定义的方法必须放在同一个包内,可以是不同的文件
    • 上面代码复制到test包中,在test02包中进行调用,需要调用的方法名首字母大写

    5. 接口

    • go语言中,接口(interface)是一个自定义类型,描述了一系列方法的集合

    • 接口不能被实例化

    • 接口定义语法如下

    • type 接口名 interface{}

    • PS:接口命名习惯以er结尾

    • 接口定义与实现

        package main
        
        import "fmt"
        
        //定义人的接口
        type Humaner interface {
           //说话
           Say()
        }
        
        //学生结构体
        type Student struct {
           name  string
           score int
        }
        
        //Student实现Say()方法
        func (s *Student) Say() {
           fmt.Printf("Student[%s,%d] 瞌睡不断
      ", s.name, s.score)
        }
        
        type Teacher struct {
           name  string
           group string
        }
        
        //老师实现接口
        func (t *Teacher) Say() {
           fmt.Printf("Teacher[%s,%s] 毁人不倦
      ", t.name, t.group)
        }
        
        //自定义类型
        type MyStr string
        
        //自定义类型实现方法
        func (str MyStr) Say() {
           fmt.Printf("MyStr[%s] 同志醒醒,还有个bug
      ", str)
        }
        
        func WhoSay(i Humaner) {
           i.Say()
        }
        
        func main() {
           s := &Student{"约汉", 88}
           t := &Teacher{"撸死", "Go语言"}
           var tmp MyStr = "接客"
        
           s.Say()
           t.Say()
           tmp.Say()
        
           //go的多态,调用同一个接口,不同表现
           WhoSay(s)
           WhoSay(t)
           WhoSay(tmp)
        
           //make()创建
           x := make([]Humaner, 3)
           x[0], x[1], x[2] = s, t, tmp
           for _, value := range x {
              value.Say()
           }
        }
      
      • 接口继承

          package main
          
          import "fmt"
          
          //定义人的接口
          type Humaner interface {
             //说话
             Say()
          }
          type Personer interface {
             //等价于写了Say()
             Humaner
             Sing(lyrics string)
          }
          
          //学生结构体
          type Student struct {
             name  string
             score int
          }
          
          //Student实现Say()方法
          func (s *Student) Say() {
             fmt.Printf("Student[%s,%d] 瞌睡不断
        ", s.name, s.score)
          }
          
          func (s *Student) Sing(lyrics string) {
             fmt.Printf("Student sing[%s]!!
        ", lyrics)
          }
          
          func main() {
             s := &Student{"约汉", 88}
             var p Personer
             p = s
             p.Say()
             p.Sing("互撸娃")
          }
        
      • 空接口:空interface{}不包含任何方法,空接客可以存储任意类型的值

      • 类型查询

        • comma-ok断言

            package main
            
            import "fmt"
            
            //空接口
            type Element interface{}
            
            type Person struct {
               name string
               age  int
            }
            
            func main() {
               //切片
               list := make([]Element, 3)
               //int
               list[0] = 1
               list[1] = "Hello"
               list[2] = Person{"luhan", 18}
               //遍历
               for index, element := range list {
                  //类型断言:value ,ok = element.(T)
                  //value 是变量的值,ok是返回的布尔值,element是接口变量,T是断言类型
                  if value, ok := element.(int); ok {
                     fmt.Printf("list[%d]是int类型,值是%d
          ", index, value)
                  } else if value, ok := element.(int); ok {
                     fmt.Printf("list[%d]是int类型,值是%d
          ", index, value)
                  } else if value, ok := element.(Person); ok {
                     fmt.Printf("list[%d]是Person类型,值是[%s,%d]
          ",
                        index, value.name, value.age)
                  } else {
                     fmt.Printf("list[%d]是其他类型
          ", index)
                  }
               }
            }
          
        • switch测试

          package main
          
          import "fmt"
          
          //空接口
          type Element interface{}
          
          type Person struct {
             name string
             age  int
          }
          
          func main() {
             //切片
             list := make([]Element, 3)
             //int
             list[0] = 1
             list[1] = "Hello"
             list[2] = Person{"luhan", 18}
             //遍历
             for index, element := range list {
                switch value := element.(type) {
                case int:
                   fmt.Printf("list[%d]是int类型,值是%d
          ", index, value)
                case string:
                   fmt.Printf("list[%d]是string类型,值是%s
          ", index, value)
                default:
                   fmt.Printf("list[%d]是其他类型
          ", index)
                }
             }
          }
  • 相关阅读:
    CentOS7搭建FTP服务器和安装FTP客户端
    Python实现网络和IP地址计算
    [Leetcode Weekly Contest]270
    [Leetcode Weekly Contest]269
    [Leetcode Weekly Contest]266
    Vue.use原理及源码解读
    Rust 程序设计语言 6
    go 语言的 Context
    Rust程序设计语言(7)
    手机界面设计中12种常用布局转载
  • 原文地址:https://www.cnblogs.com/konghui/p/10703599.html
Copyright © 2011-2022 走看看