GO基礎之接口

1、概念
一、 面嚮對象語言中,接口用於定義對象的行爲。接口只指定對象應該作什麼,實現這種行爲的方法(實現細節)是由對象來決定。
二、 在Go語言中,接口是一組方法簽名。java

  • •接口只指定了類型應該具備的方法,類型決定了如何實現這些方法。
  • •當某個類型爲接口中的全部方法提供了具體的實現細節時,這個類型就被稱爲實現了該接口。
  • •接口定義了一組方法,若是某個對象實現了該接口的全部方法,則此對象就實現了該接口。

三、 Go語言的類型都是隱式實現接口的。任何定義了接口中全部方法的類型都被稱爲隱式地實現了該接口。golang

 

2、接口的使用

go沒有 implements, extends 關鍵字,其實這種編程語言叫作duck typing編程語言。編程

package main

import "fmt"
import "base"

//定義接口
type Phone interface {
    call()
}

type AndroidPhone struct {
}

type IPhone struct {
}

func (a AndroidPhone) call() {
    fmt.Println("我是安卓手機,能夠打電話了")
}

func (i IPhone) call() {
    fmt.Println("我是蘋果手機,能夠打電話了")
}

func main() {
    //    定義接口類型的變量
    var phone Phone
    //phone = new(AndroidPhone)
    phone = AndroidPhone{}
    fmt.Printf("%T , %v , %p \n" , phone , phone , &phone)
    phone.call()

    //phone = new(IPhone)
    phone = IPhone{}
    fmt.Printf("%T , %v , %p \n" , phone , phone , &phone)
    phone.call()
}
View Code


 動態類型與靜態類型語言app

  • •動態類型的好處不少,Python代碼寫起來很快。可是缺陷也是顯而易見的:錯誤每每要在運行時才能被發現。
  • •相反,靜態類型語言每每在編譯時就是發現這類錯誤:若是某個變量的類型沒有顯式聲明實現了某個接口,那麼,這個變量就不能用在要求一個實現了這個接口的地方。

 Go類型系統採起了折中的辦法:
•之因此說這是一種折中的辦法,緣由以下:編程語言

  • 〇第一,結構體類型T不須要顯式地聲明它實現了接口 I。只要類型T實現了接口1規定的全部方法,它就自動地實現了接口 I。這樣就像動態語言同樣省了不少代碼,少了許多限制。
  • 〇第二,將結構體類型的變量顯式或者隱式地轉換爲接口 I類型的變量i。這樣就能夠和其它靜態類型語言同樣,在編譯時檢查參數的合法性。

3、多態

•事物的多種形態ide

  • • Go中的多態性是在接口的幫助下實現的。定義接口類型,倉U建實現該接口的結構體對象。
  • •定義接口類型的對象,能夠保存實現該接口的任何類型的值。Go語言接口變量的這個特性實現了 Go語言中的多態性。
  • •接口類型的對象,不能訪問其實現類中的屬性字段。

 

package main

import "fmt"
import "base"


type Income interface {
    calculate() float64 //計算收入總額
    source() string     //用來講明收入來源
}

//固定帳單項目
type FixedBilling struct {
    projectName  string  //工程項目
    biddedAmount float64 //項目招標總額
}

//定時生產項目(定時和材料項目)
type TimeAndMaterial struct {
    projectName string
    workHours   float64 //工做時長
    hourlyRate  float64 //每小時工資率
}

//固定收入項目
func (f FixedBilling) calculate() float64 {
    return f.biddedAmount
}

func (f FixedBilling) source() string {
    return f.projectName
}

//定時收入項目
func (t TimeAndMaterial) calculate() float64 {
    return t.workHours * t.hourlyRate
}

func (t TimeAndMaterial) source() string {
    return t.projectName
}

//經過廣告點擊得到收入
type Advertisement struct {
    adName         string
    clickCount     int
    incomePerclick float64
}

func (a Advertisement) calculate() float64 {
    return float64(a.clickCount) * a.incomePerclick
}

func (a Advertisement) source() string {
    return a.adName
}

func main() {
    p1 := FixedBilling{"項目1", 5000}
    p2 := FixedBilling{"項目2", 10000}
    p3 := TimeAndMaterial{"項目3", 100, 40}
    p4 := TimeAndMaterial{"項目4", 250, 20}
    p5 := Advertisement{"廣告1", 10000, 0.1}
    p6 := Advertisement{"廣告2", 20000, 0.05}

    ic := []Income{p1, p2, p3, p4, p5, p6}
    fmt.Println("total=",calculateNetIncome(ic))
}

//計算淨收入
func calculateNetIncome(ic []Income) float64 {
    netincome := 0.0
    for _, income := range ic {
        fmt.Printf("收入來源:%s ,收入金額:%.2f \n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    return netincome
}
View Code

 

4、空接口

•空接口 :該接口中沒有任何的方法。任意類型均可以實現該接口。
•空interface這樣定義:interface{},也就是包含0個method的interface。
•用空接口表示任意數據類型。相似於java中的object。
•空接口經常使用於如下情形:
〇 一、println的參數就是空接口
〇 二、定義一個map: key是string,value是任意數據類型
〇 三、定義一個切片,其中存儲任意類型的數據url

package main

import (
    "fmt"
)

type A interface {
}

type Cat struct {
    name string
    age  int
}

type Person struct {
    name string
    sex  string
}

func main() {
    var a1 A = Cat{"Mimi", 1}
    var a2 A = Person{"Steven", ""}
    var a3 A = "Learn golang with me!"
    var a4 A = 100
    var a5 A = 3.14

    showInfo(a1)
    showInfo(a2)
    showInfo(a3)
    showInfo(a4)
    showInfo(a5)
    fmt.Println("------------------")

    //一、fmt.println參數就是空接口
    fmt.Println("println的參數就是空接口,能夠是任何數據類型", 100, 3.14, Cat{"旺旺", 2})

    //二、定義map。value是任何數據類型
    map1 := make(map[string]interface{})
    map1["name"] = "Daniel"
    map1["age"] = 13
    map1["height"] = 1.71
    fmt.Println(map1)
    fmt.Println("------------------")

    //    三、定義一個切片,其中存儲任意數據類型
    slice1 := make([]interface{}, 0, 10)
    slice1 = append(slice1, a1, a2, a3, a4, a5)
    fmt.Println(slice1)

    transInterface(slice1)

    //var cat1 A = Cat{"MiaoMiao" , 3}
    //fmt.Println(cat1.name , cat1.age)

}

//接口對象轉型
//接口對象.(type),配合switch...case語句
func transInterface(s []interface{}) {
    for i := range s {
        fmt.Println("", i+1 , "個數據:")
        switch t := s[i].(type) {
        case Cat:
            fmt.Printf("\t Cat對象,name屬性:%s,age屬性:%d \n" , t.name , t.age)
        case Person:
            fmt.Printf("\t Person對象,name屬性:%s,sex屬性:%s \n" , t.name , t.sex)
        case string:
            fmt.Println("\t string類型" , t)
        case int:
            fmt.Println("\t int類型" , t)
        case float64:
            fmt.Println("\t float64類型" , t)
        }
    }
}

func showInfo(a A) {
    fmt.Printf("%T , %v \n", a, a)
}
View Code

5、接口對象轉型
一、 方式一:
• instance, ok :=接口對象.(實際類型)
•若是該接口對象是對應的實際類型,那麼instance就是轉型以後對象,ok的值爲true
•配合if... else if...語句使用
二、 方式二:
•接口對象.(type)
•配合switch...case語句使用spa

package main

import "fmt"
import (
    "base"
    "math"
)

//一、定義接口
type Shape interface {
    perimeter() float64
    area() float64
}

//2.矩形
type Rectangle struct {
    a, b float64
}

//3.三角形
type Triangle struct {
    a, b, c float64
}

//4.圓形
type Circle struct {
    radius float64
}

//定義實現接口的方法
func (r Rectangle) perimeter() float64 {
    return (r.a + r.b) * 2
}

func (r Rectangle) area() float64 {
    return r.a * r.b
}

func (t Triangle) perimeter() float64 {
    return t.a + t.b + t.c
}

func (t Triangle) area() float64 {
    //海倫公式
    p := t.perimeter() / 2 //半周長
    return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
}

func (c Circle) perimeter() float64 {
    return 2 * math.Pi * c.radius
}

func (c Circle) area() float64 {
    return math.Pow(c.radius, 2) * math.Pi
}

//接口對象轉型方式1
//instance,ok := 接口對象.(實際類型)
func getType(s Shape) {
    if instance, ok := s.(Rectangle); ok {
        fmt.Printf("矩形:長度%.2f , 寬度%.2f , ", instance.a, instance.b)
    } else if instance, ok := s.(Triangle); ok {
        fmt.Printf("三角形:三邊分別:%.2f , %.2f , %.2f , ", instance.a, instance.b, instance.c)
    } else if instance, ok := s.(Circle); ok {
        fmt.Printf("圓形:半徑%.2f , ", instance.radius)
    }
}

//接口對象轉型——方式2
//接口對象.(type),  配合switch和case語句使用
func getType2(s Shape) {
    switch instance := s.(type) {
    case Rectangle:
        fmt.Printf("矩形:長度爲%.2f , 寬爲%.2f ,\t", instance.a, instance.b)
    case Triangle:
        fmt.Printf("三角形:三邊分別爲%.2f ,%.2f , %.2f ,\t", instance.a, instance.b, instance.c)
    case Circle:
        fmt.Printf("圓形:半徑爲%.2f ,\t", instance.radius)
    }
}

func getResult(s Shape) {
    getType2(s)
    fmt.Printf("周長:%.2f ,面積:%.2f \n", s.perimeter(), s.area())
}

func main() {
    var s Shape
    s = Rectangle{3, 4}
    getResult(s)
    showInfo(s)

    s = Triangle{3, 4, 5}
    getResult(s)
    showInfo(s)

    s = Circle{1}
    getResult(s)
    showInfo(s)

    x := Triangle{3, 4, 5}
    fmt.Println(x)

}

func (t Triangle) String() string {
    return fmt.Sprintf("Triangle對象,屬性分別爲:%.2f, %.2f, %.2f", t.a, t.b, t.c)
}

func showInfo(s Shape) {
    fmt.Printf("%T ,%v \n", s, s)
    fmt.Println("-------------------")
}
View Code
相關文章
相關標籤/搜索