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)
                }
             }
          }
  • 相关阅读:
    路径变量@PathVariable/请求参数@RequestParam的绑定以及@RequestBody
    JSR303后端校验详细笔记
    创建ssm项目步骤
    利用 R 绘制拟合曲线
    在 Linux 中将 Caps 根据是否为修饰键分别映射到 esc 和 Ctrl
    Master Transcription Factors and Mediator Establish Super-Enhancers at Key Cell Identity Genes
    Genomic Evidence for Complex Domestication History of the Cultivated Tomato in Latin America
    Variation Revealed by SNP Genotyping and Morphology Provides Insight into the Origin of the Tomato
    The genetic, developmental, and molecular bases of fruit size and shape variation in tomato
    微信支付jsapi
  • 原文地址:https://www.cnblogs.com/konghui/p/10703599.html
Copyright © 2011-2022 走看看