接口
1、定义
Interface类型可以定义一组方法,用来表示一个对象的行为特征。
interface不能包含任何变量。
type Animal interface{ Talk(参数列列表) 返回值列列表 Eat(参数列列表) 返回值列列表
… }
2、 interface类型是引用类型
3、接口实现
a. Golang中的接口,不需要显示的实现。只要 一个对象,实现了接口类型中的所有方法,那么这个对象就实现这个接口。
b. 如果一个对象实现了多个interface类型的方法,那么这个对象就实现了多个接口。
package main import ( "fmt" ) type Animal interface { Eat() Talk() } type Dog struct { } func (d *Dog) Eat() { fmt.Println("dog is eating") } func (d *Dog) Talk() { fmt.Println("dog is wawa!") } type Cat struct { } func (d *Cat) Eat() { fmt.Println("cat is eating") } func (d *Cat) Talk() { fmt.Println("cat is miaomiao!") } func main() { var a Animal //a.Eat() //报错,接口是引用类型 var d Dog d.Eat() a = &d a.Eat() var c Cat a = &c a.Eat() }
4、多态
一种事物的多种形态,都可以按照统 一的接口进行操作
package main import ( "fmt" ) type Animal interface { Eat() Talk() } type Dog struct { Name string } func (d *Dog) Eat() { fmt.Println(d.Name, "is eating") } func (d *Dog) Talk() { fmt.Println(d.Name, " is wawa!") } type Cat struct { Name string } func (d *Cat) Eat() { fmt.Println(d.Name, "is eating") } func (d *Cat) Talk() { fmt.Println(d.Name, "is 喵喵!") } func main() { var animalList []Animal //定义一个接口类型的切片 d := &Dog{ Name: "小黄", } animalList = append(animalList, d) d1 := &Dog{ Name: "旺财", } animalList = append(animalList, d1) c1 := &Cat{ Name: "小白", } animalList = append(animalList, c1) for _, v := range animalList { v.Eat() v.Talk() } }
5、空接口,Interface{}
空接口没有任何方法,所以所有类型都实现了空接口。
package main import ( "fmt" ) func main(){ var a interface{} //可以存所有的数据类型,一般不用,尽量使用强类型的数据类型,代码便于维护 var b int = 1000 a = b fmt.Println(a) var c string = "hello" a = c fmt.Println(a) }
6、接口嵌套
一个接口可以嵌套在另外的接口(实例必须实现所有接口内的方法)
package main import ( "fmt" ) type Eater interface { Eat() } type Talker interface { Talk() } type Animal interface { Eater Talker } func main() { d := &Dog{} var a Animal a = d a.Eat() }
7、类型断言。如果我们反向要知道这个接口变量里面实际存储的是哪个类型的对象可以采用以下方法进行转换:
var t int var x interface{} x = t y = x.(int)//转成int var t int var x interface{} x = t y, ok = x.(int) //转成int,带检查
package main import ( "fmt" ) type Eater interface { Eat() } type Talker interface { Talk() } type Animal interface { Eater Talker } type Dog struct { } func (d *Dog) Eat() { fmt.Println("eating") } func (d *Dog) Talk() { fmt.Println("eating") } type Cat struct { } func (c *Cat) Eat() { fmt.Println("eating") } func (c *Cat) Talk() { fmt.Println("eating") } func justify(a Animal) { dog, ok := a.(*Dog) //类型断言,判断类型里面存的是Dog,还是Cat if !ok { fmt.Println("conver to dog failed") return } dog.Eat() } func main() { d := &Dog{} var a Animal a = d a.Eat() justify(a) a = &Cat{} justify(a) }
8、类型断言,采用type switch 方式
package main import ( "fmt" ) func justify(items ...interface{}) { for index, v := range items { switch v.(type) {//类型断言 case int: fmt.Printf("第 %d 个参数 is int ", index) case int32: fmt.Printf("第 %d 个参数 is int32 ", index) case float32: fmt.Printf("第 %d 个参数 is float32 ", index) } } } func main(){ var a int var b float32 var c int32 justify(a, b, c) }
package main import ( "fmt" ) type Eater interface { Eat() } type Talker interface { Talk() } type Animal interface { Eater Talker } type Dog struct { } func (d *Dog) Eat() { fmt.Println("eating") } func (d *Dog) Talk() { fmt.Println("eating") } type Cat struct { } func (c *Cat) Eat() { fmt.Println("eating") } func (c *Cat) Talk() { fmt.Println("eating") } func justify(a Animal) { switch t := a.(type) { case *Dog: t.Eat() fmt.Printf("t is dog ") case *Cat: t.Eat() fmt.Printf("t is cat ") } } func main() { d := &Dog{} var a Animal a = d a.Eat() justify(a) a = &Cat{} justify(a) }
9、判断 一个变量是否实现了指定接口
type Stringer interface { String() string } v := &MyStruct{} var tmp interface{} = v if sv, ok :=tmp.(Stringer); ok { fmt.Printf(“v implements String(): %s ”, sv.String()); }
课后练习:
实现一个负载均衡调度算法, 支持随机、轮询等算法
package main import ( "fmt" "math/rand" ) func doBalance(balance Balance, addrList []string) (addr string) { return balance.DoBalance(addrList) } func main() { var addrList []string for i := 0; i < 5; i++ { addr := fmt.Sprintf("%d.%d.%d.%d:8080", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255)) //根据于格式说明符进行格式化并返回其结果字符串。 addrList = append(addrList, addr) } var balanceName string fmt.Scanf("%s", &balanceName) //从控制台读取 var balance Balance if balanceName == "random" { balance = &RandBalance{} } else if balanceName == "roundrobin" { balance = &RoundBalance{} } else { balance = &RandBalance{} } for i := 0; i < 10; i++ { addr := doBalance(balance, addrList) fmt.Println(addr) } }
接口:
package main type Balance interface { DoBalance([]string) string }
随机算法:
package main import ( "math/rand" ) type RandBalance struct { } func (r *RandBalance) DoBalance(addrList []string) string { l := len(addrList) index := rand.Intn(l) return addrList[index] }
轮询算法:
package main type RoundBalance struct { curIndex int } func (r *RoundBalance) DoBalance(addrList []string) string { l := len(addrList) r.curIndex = r.curIndex % l addr := addrList[r.curIndex] r.curIndex++ return addr }
手机支付接口的实现:
package main import( "fmt" ) func main(){ phone := &Phone{ PayMap:make(map[string]Pay, 16), } //phone.OpenWeChatPay() //开通微信支付 //phone.OpenAliPay() //开通阿里支付 weChat := &WeChatPay{} var tmp interface{} = weChat _, ok := tmp.(Pay) //tmp这个变量是否实现了Pay这个接口 if ok { fmt.Println("weChat is implement Pay interface") } phone.OpenPay("ali_pay", &AliPay{}) //开通阿里支付 err := phone.PayMoney("wechat_pay", 20.32) if err != nil { fmt.Printf("支付失败,失败原因:%v ", err) fmt.Printf("使用支付宝支付 ") err = phone.PayMoney("ali_pay", 20.32) if err != nil { fmt.Printf("支付失败,失败原因:%v ", err) return } } fmt.Println("支付成功,欢迎再次光临!") }
支付接口:
package main type Pay interface { pay(user_id int64, money float32) error }
alipay支付:
package main import ( "fmt" ) type AliPay struct { } func (a *AliPay) pay(user_id int64, money float32) error { fmt.Println("1. 连接到阿里的服务器") fmt.Println("2. 找到对应的用户") fmt.Println("3. 扣钱") fmt.Println("4. 返回支付是否成功") fmt.Println("5. 连接到阿里的服务器") fmt.Println("6. 找到对应的用户") fmt.Println("7. 扣钱") fmt.Println("8. 返回支付是否成功") return nil }
weixin支付:
package main import ( "fmt" ) type WeChatPay struct { } func (w *WeChatPay) pay(user_id int64, money float32) error { fmt.Println("1. 连接到微信支付的服务器") fmt.Println("2. 找到对应的用户") fmt.Println("3. 检查余额是否充足") fmt.Println("4. 扣钱") fmt.Println("5. 返回支付是否成功") return nil }
具体支付实现:
package main import ( "fmt" ) type Phone struct { PayMap map[string]Pay //Pay为接口 } func (p *Phone) OpenWeChatPay() { weChatPay := &WeChatPay{} p.PayMap["wechat_pay"] = weChatPay } func (p *Phone) OpenAliPay() { aliPay := &AliPay{} p.PayMap["ali_pay"] = aliPay } func (p *Phone) OpenPay(name string, pay Pay) { p.PayMap[name] = pay } func (p *Phone) PayMoney(name string, money float32) (err error) { pay, ok := p.PayMap[name] if !ok { err = fmt.Errorf("不支持[%s]支付方式", name) return } err = pay.pay(1023, money) return }
结构体排序的方法:
package main import ( "sort" "math/rand" "fmt" ) type Student struct { name string age int score float32 } type StudentSlice []*Student func (p StudentSlice) Len() int { return len(p) } func (p StudentSlice) Less(i, j int) bool { return p[i].score > p[j].score } func (p StudentSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func main() { var studentArr StudentSlice for i := 0; i < 10; i++ { var s = &Student { name: fmt.Sprintf("李%d", i), age: rand.Intn(100), score: rand.Float32()*100, } studentArr = append(studentArr, s) } sort.Sort(studentArr) //排序,studentArr实现了Interface接口的方法 for i := 0; i < len(studentArr); i++{ fmt.Printf("%#v ", studentArr[i]) } }
冒泡排序的接口实现方式:
package main import ( "math/rand" "fmt" ) type Student struct { name string age int score float32 } type StudentSlice []*Student func (p StudentSlice) Len() int { return len(p) } func (p StudentSlice) Less(i, j int) bool { return p[i].score > p[j].score } func (p StudentSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func main() { var studentArr StudentSlice for i := 0; i < 10; i++ { var s = &Student { name: fmt.Sprintf("李%d", i), age: rand.Intn(100), score: rand.Float32()*100, } studentArr = append(studentArr, s) } bubble_sort(studentArr) for i := 0; i < len(studentArr); i++{ fmt.Printf("%#v ", studentArr[i]) } }
package main type SortInterface interface { Len() int Less(i, j int) bool Swap(i, j int) } func bubble_sort(a SortInterface) { for i := a.Len() -1; i > 0; i-- { for j := 0; j < i; j++ { //if a[j] > a[j+1] { if a.Less(j+1, j) { //a[j], a[j+1] = a[j+1], a[j] a.Swap(j, j+1) } } } }
反射
反射:可以在运行时动态获取变量的相关信息
import (“reflect”)
两个函数:
a.reflect.TypeOf(),获取变量的类型,返回reflect.Type类型
b.reflect.Type.Kind(),获取变量的类型,返回变量的类型(如struct、int)
c.reflect.ValueOf(),获取变量的值,返回reflect.Value类型
d.reflect.Value.Kind(),获取变量的类型,返回变量的类型(如struct、int)
d.reflect.Value.Type(),获取变量的名称,返回变量的名称(如student)
e.reflect.Value.Interface(),转换成interface{}类型
2、reflect.Value.Kind() 方法返回的常量
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
4.获取变量量的值:
reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()
package main import ( "reflect" "fmt" ) type Student struct { Name string } func (s *Student) Set(name string , Age int, Sex int) { s.Name = name } func (s *Student) GetName(name string) { s.Name = name } func getAllMethod(a interface{}) { typeInfo := reflect.TypeOf(a) num := typeInfo.NumMethod() //获取结构体有多少个方法,2个 for i := 0;i <num; i++{ method := typeInfo.Method(i) //类型的具体方法是什么 fmt.Println(method) } } func getTypeInfo(a interface{}) { typeInfo := reflect.TypeOf(a) kind := typeInfo.Kind() fmt.Println("kind of a:", kind) num := typeInfo.NumMethod() fmt.Println("method num:", num) method, ok := typeInfo.MethodByName("SetName") if !ok { fmt.Println("not have method SetName") } else { fmt.Println(method) } fmt.Println() fmt.Println() } func testGetTypeInfo() { var i int getTypeInfo(i) //获取int变量的类型 var stu Student getTypeInfo(&stu) //获取结构体的类型 var s [5]int getTypeInfo(s) //获取数组的类型 } func testGetAllMethod() { var stu Student getAllMethod(&stu) //获取结构体的方法 } func testGetValuInfo() { var i int = 100 valueInfo := reflect.ValueOf(&i) //valueInfo是一个结构体,要改变值必须传指针进去 valueInfo.Elem().SetInt(200) //Elem()获取指针指向的变量 tmp := valueInfo.Interface() //将结构体转为一个空接口 val := tmp.(*int) //将结构体转为原来的值 fmt.Println("val:", val) fmt.Println("val of valueInfo:", valueInfo.Elem().Int()) //200 fmt.Println("type:", valueInfo.Type()) //int fmt.Println("kind:", valueInfo.Kind()) //int fmt.Println("i=", i) var stu Student valueInfo = reflect.ValueOf(stu) fmt.Println("type:", valueInfo.Type()) //main.Student fmt.Println("kind:", valueInfo.Kind()) //类别为struct } func main() { //testGetTypeInfo() //testGetAllMethod() testGetValuInfo() }
5、通过反射的来改变量的值
reflect.Value.SetXX相关方法, 比如:
reflect.Value.SetFloat(),设置浮点数
reflect.Value.SetInt(),设置整数
reflect.Value.SetString(),设置字符串
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Sex int } func (s *Student) Set(name string , Age int, Sex int) { s.Name = name s.Age = Age s.Sex = Sex } func (s *Student) GetName(name string) { s.Name = name } func testStruct () { var stu *Student = &Student{} stu.Set("jim", 18, 1) //结构体赋值 valueInfo := reflect.ValueOf(stu) fieldNum := valueInfo.Elem().NumField() //获取结构体中字段的个数 fmt.Println("field name:", fieldNum) sexValueInfo := valueInfo.Elem().FieldByName("Sex") //通过字段名,找到相应的字段,返回的是一个结构体 fmt.Println("sex=", sexValueInfo.Int()) sexValueInfo.SetInt(100) //修改sex字段 fmt.Println(stu) setMethod := valueInfo.MethodByName("Set") //调用结构体的方法 fmt.Println(setMethod) var params []reflect.Value name := "Tom" age := 1000 sex := 3883 params = append(params, reflect.ValueOf(name)) params = append(params, reflect.ValueOf(age)) params = append(params, reflect.ValueOf(sex)) setMethod.Call(params) //调用结构体的方法,params要传一个切片进去 fmt.Println(stu) } func main() { testStruct() }