Golang 接口 Interface

interface 接口类型是对其他类型的抽象和概括,通过接口,我们的函数可以不用绑定在一个特定的类型上

接口实现

  • 一个类型如何实现接口:实现这个类型的所有方法
  • 一个类型可以实现多个接口。

一个例子

package main

import (
	"fmt"
)

// Animal ...
type Animal interface {
	ActingCute()
}

// Cat ...
type Cat struct {
}

// ActingCute ...
func (c *Cat) ActingCute() {
	fmt.Println("喵星人喵喵喵来卖萌")
}

func main() {
    var am Animal
	cat := &Cat{}
    cat.ActingCute()
    fmt.Print("am....\n")
    am.ActingCute()
}
喵星人喵喵喵来卖萌
am....
喵星人喵喵喵来卖萌
  • Cat类型实现了Animal接口
  • am是一个Animal接口类型变量,现在am指向了一个Cat类型,通过它可以调用 Cat 上的方法 ActingCute(),即:am.ActingCute(),也可以直接在 Cat 的实例上调用此方法,即:cat.ActingCute(),但是第一种方式显得更有通用性。
  • 这也是 多态,根据当前的类型选择正确的方法,或者说:同一种类型在不同的实例上表现出不同的行为。

一个更加形象的例子

package main

import (
	"fmt"
)

// Animal ...
type Animal interface {
	ActingCute()
}

// Cat ...
type Cat struct {
}

// Dog ...
type Dog struct {
}

// ActingCute ...
func (c *Cat) ActingCute() {
	fmt.Println("喵星人喵喵喵来卖萌")
}

// ActingCute ...
func (d *Dog) ActingCute() {
	fmt.Println("狗星人汪汪汪来卖萌")
}

func main() {
	var ams []Animal
	cat := &Cat{}
	cat.ActingCute()
	dog := &Dog{}
	ams = append(ams, cat)
	ams = append(ams, dog)
	fmt.Print("ams....\n")
	for _, am := range ams {
		am.ActingCute()
	}
	return
}

喵星人喵喵喵来卖萌
ams....
喵星人喵喵喵来卖萌
狗星人汪汪汪来卖萌

  • am.ActingCute() 对于不同的实现出现了不同的行为

接口嵌套接口

package main

import "fmt"

type discount interface {
	offer() float64
}

type giftpack interface {
	available() string
}

type catalog interface {
	discount
	giftpack
	shipping() float64
	tax() float64
}

如何检测和转换接口变量的类型

类型断言
  • 一个接口类型的变量 varI 中可以包含任何类型的值,必须有一种方式来检测它的 动态 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 类型断言 来测试在某个时刻 varI 是否包含类型 T 的值:
if v, ok := varI.(T); ok {  // 类型断言
    Process(v)
    return
}
// varI is not of type T
  • 如果转换合法,vvarI 转换到类型 T的值,ok 会是 true;否则 v 是类型 T的零值,okfalse,也没有运行时错误发生。

  • 类型判断:type-switch

switch t := an.(type) {
case *Cat:
	fmt.Printf("Type Cat %T with value %v\n", t, t)
case *Dog:
	fmt.Printf("Type Dog %T with value %v\n", t, t)
case nil:
	fmt.Printf("nil value: nothing to check?\n")
default:
	fmt.Printf("Unexpected type %T\n", t)
}
反射机制
  • 什么是反射机制?
    在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
  • 使用反射的场景?
    Go 语言中使用反射的场景:有时候需要根据某些条件决定调用哪个函数,比如根据用户的输入来决定,但事先无法不知道接受到的参数是什么类型,全部以 interface{} 类型接受。这时就需要对函数的参数进行反射,在运行期间动态地执行函数。
  • reflect 包
    • reflect.TypeOf 和 reflect.ValueOf 来动态获得类型信息和实际值(reflect.Type,reflect.Value)
    • Type()、Kind()
    1. reflect.Value 的 Type() 方法返回实际类型信息;2. reflect.Type 和 reflect.Value 都有 Kind() 方法,来获得实际值的底层类型,结果对应的是 reflect 包中定义的常量;3. reflect.Value 的那些以类型名为方法名的方法,比如 Int()、Float(),能获得实际值。
package main

import (
	"fmt"
	"io"
	"reflect"
	"strings"
)

func main() {

	test1()
	fmt.Println("---------------")
	test2()
}

func test1() {
	var x float64 = 3.4
	fmt.Printf("type:%s\n", reflect.TypeOf(x))   // type: float64
	fmt.Printf("value:%f\n", reflect.ValueOf(x)) // value:3.400000
	var r io.Reader = strings.NewReader("Hello")
	fmt.Println("type:", reflect.TypeOf(r)) // type: *strings.Reader
}
func test2() {
	type MyInt int
	var x MyInt = 7
	v := reflect.ValueOf(x)
	fmt.Println("type:", v.Type())
	fmt.Println("kind is int:", v.Kind() == reflect.Int)
	fmt.Println("value:", v.Int())
}

测试一个值是否实现了某个接口

type Animal interface {
    ActingCute()
}

if sv, ok := v.(Animal); ok {
    fmt.Print("v implements Animal()\n") // note: sv, not v
}

关于Interface几点问题

  • https://segmentfault.com/q/1010000020302054
  • https://ask.csdn.net/questions/690562

你可能感兴趣的:(Golang)