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
    • 結構體類型code

      //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\n",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\n", 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\n", 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\n", 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] 瞌睡不斷\n", s.name, s.score)
      }
    
      type Teacher struct {
         name  string
         group string
      }
    
      //老師實現接口
      func (t *Teacher) Say() {
         fmt.Printf("Teacher[%s,%s] 毀人不倦\n", t.name, t.group)
      }
    
      //自定義類型
      type MyStr string
    
      //自定義類型實現方法
      func (str MyStr) Say() {
         fmt.Printf("MyStr[%s] 同志醒醒,還有個bug\n", 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] 瞌睡不斷\n", s.name, s.score)
        }
      
        func (s *Student) Sing(lyrics string) {
           fmt.Printf("Student sing[%s]!!\n", 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\n", index, value)
                } else if value, ok := element.(int); ok {
                   fmt.Printf("list[%d]是int類型,值是%d\n", index, value)
                } else if value, ok := element.(Person); ok {
                   fmt.Printf("list[%d]是Person類型,值是[%s,%d]\n",
                      index, value.name, value.age)
                } else {
                   fmt.Printf("list[%d]是其餘類型\n", 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\n", index, value)
              case string:
                 fmt.Printf("list[%d]是string類型,值是%s\n", index, value)
              default:
                 fmt.Printf("list[%d]是其餘類型\n", index)
              }
           }
        }
相關文章
相關標籤/搜索