接口

1. 定义: Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。

type example interface{
Method1(参数列表) 返回值列表
Method2(参数列表) 返回值列表
}

2.interface类型默认是一个指针

	type example interface{

			Method1(参数列表) 返回值列表
Method2(参数列表) 返回值列表

} var a example
a.Method1()

3. 接口实现

  • a. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
  • b. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
  • c. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。
package main

import "fmt"

type Car interface {
GetName() string
Run()
DiDi()
} type Test interface {
Hello()
} type BMW struct {
Name string
} func (p *BMW) GetName() string {
return p.Name
} func (p *BMW) Run() {
fmt.Printf("%s is running\n", p.Name)
} func (p *BMW) DiDi() {
fmt.Printf("%s is didi\n", p.Name)
}
func (p *BMW) Hello() {
fmt.Printf("%s is hello\n", p.Name)
} type BYD struct {
Name string
} func (p *BYD) GetName() string {
return p.Name
} func (p *BYD) Run() {
fmt.Printf("%s is running\n", p.Name)
} func (p *BYD) DiDi() {
fmt.Printf("%s is didi\n", p.Name)
} func main() {
var car Car
var test Test
fmt.Println(car) // var bwm = BMW{}
// bwm.Name = "宝马"
bwm := &BMW{
Name: "宝马",
}
car = bwm
car.Run() test = bwm
test.Hello() byd := &BMW{
Name: "比亚迪",
}
car = byd
car.Run()
// var a interface{}
// var b int
// var c float32 // a = b
// a = c
// fmt.Printf("type of a %T\n", a)
}

接口实现案例Car

4.多态:一种事物的多种形态,都可以按照统一的接口进行操作

sort排序

package main

import (
"fmt"
"math/rand"
"sort"
) type Student struct {
Name string
Id string
Age int
} type Book struct {
Name string
Author string
} type StudentArray []Student func (self StudentArray) Len() int {
return len(self)
} func (self StudentArray) Less(i, j int) bool {
return self[i].Name > self[j].Name
} func (self StudentArray) Swap(i, j int) {
self[i], self[j] = self[j], self[i]
} func main() {
var stus StudentArray for i := 0; i < 10; i++ {
stu := Student{
Name: fmt.Sprintf("stu%d", rand.Intn(100)),
Id: fmt.Sprintf("110%d", rand.Int()),
Age: rand.Intn(100),
}
stus = append(stus, stu)
} for _, v := range stus {
fmt.Println(v)
} fmt.Println() sort.Sort(stus) for _, v := range stus {
fmt.Println(v)
}
}

5. 接口嵌套:一个接口可以嵌套在另外的接口,如下所示:

type ReadWrite interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type Lock interface {
Lock()
Unlock()
}
type File interface {
ReadWrite
Lock
Close()
}
package main

import "fmt"

type Reader interface {
Read()
} type Writer interface {
Write()
} type ReadWriter interface {
Reader
Writer
} type File struct {
} func (self *File) Read() {
fmt.Println("read data")
} func (self *File) Write() {
fmt.Println("write data")
} func Test(rw ReadWriter) {
rw.Read()
rw.Write()
} func main() {
var f *File
var b interface{}
b = f
// Test(f) v, ok := b.(ReadWriter)
fmt.Println(v, ok)
}

接口嵌套文件读写案例

6. 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法进行转换:

	var t int
var x interface{}
x = t
y, ok = x.(int) //转成int,带检查

7. 练习,写一个函数判断传入参数的类型

package main

import (
"fmt"
) type Studnet struct {
Name string
Sex string
} func Test(a interface{}) {
// b, ok := a.(int)
b, ok := a.(Studnet)
if ok == false {
fmt.Println("convert failed")
return
}
// b += 3
fmt.Println(b)
} func just(items ...interface{}) {
for index, v := range items {
switch v.(type) {
case bool:
fmt.Printf("%d params is bool, value is %v\n", index, v)
case int, int32, int64:
fmt.Printf("%d params is int, value is %v\n", index, v)
case float32, float64:
fmt.Printf("%d params is float, value is %v\n", index, v)
case string:
fmt.Printf("%d params is string, value is %v\n", index, v)
case Studnet:
fmt.Printf("%d params is student, value is %v\n", index, v)
case *Studnet:
fmt.Printf("%d params is *student, value is %v\n", index, v)
}
}
} func main() {
var a interface{}
var b int
Test(b)
a = b
c := a.(int)
fmt.Printf("%d %T\n", a, a)
fmt.Printf("%d %T\n", c, c) var d Studnet = Studnet{
Name: "stu1",
Sex: "female",
}
Test(d)
just(28, 8.2, "this is a test", d, &d)
}

8. 类型断言,采用type switch方式

9. 空接口.interface{}

  空接口没有任何方法,所以所有类型都实现了空接口。

	var a int
var b interface{}
b = a

10.判断一个变量是否实现了指定接口

	type Stringer interface {
String() string
}
var v MyStruct
if sv, ok := v.(Stringer); ok {
fmt.Printf(“v implements String(): %s\n”, sv.String());
}

11. 实现一个通用的链表类

link.go

package main

import (
"fmt"
) type LinkNode struct {
data interface{}
next *LinkNode
} type Link struct {
head *LinkNode
tail *LinkNode
} func (p *Link) InsertHead(data interface{}) {
node := &LinkNode{
data: data,
next: nil,
} if p.tail == nil && p.head == nil {
p.tail = node
p.head = node
return
} node.next = p.head
p.head = node
}
func (p *Link) InsertTail(data interface{}) {
node := &LinkNode{
data: data,
next: nil,
} if p.tail == nil && p.head == nil {
p.tail = node
p.head = node
return
} p.tail.next = node
p.tail = node
} func (p *Link) Trans() {
q := p.head
for q != nil {
fmt.Println(q.data)
q = q.next
}
}

main.go

package main

func main() {
var initLink Link
for i := 0; i < 10; i++ {
// initLink.InsertHead(i)
initLink.InsertTail(i)
}
initLink.Trans()
}

12. interface{},接口中一个方法也没有,所以任何类型都实现了空接口,也就是任何变量都可以赋值给空接口。

	var a int
var b interface{}
b = a

13.  变量slice和接口slice之间赋值操作,for range  

	var a []int
var b []interface{}
b = a

14. 实现一个负载均衡调度算法,支持随机、轮训等算法

  • balance
package balance

type Balancer interface {
DoBalance([]*Instance, ...string) (*Instance, error)
}

balance.go

package balance

import "strconv"

type Instance struct {
host string
port int
} func NewInstance(host string, port int) *Instance {
return &Instance{
host: host,
port: port,
}
} func (p *Instance) GetHost() string {
return p.host
} func (p *Instance) GetPort() int {
return p.port
} func (p *Instance) String() string {
return p.host + ":" + strconv.Itoa(p.port)
}

instance.go

package balance

import "fmt"

type BalanceMgr struct {
allBalancer map[string]Balancer
} var mgr = BalanceMgr{
allBalancer: make(map[string]Balancer),
} func (p *BalanceMgr) RegisterBalancer(name string, b Balancer) {
p.allBalancer[name] = b
} func RegisterBalancer(name string, b Balancer) {
mgr.RegisterBalancer(name, b)
} func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
balancer, ok := mgr.allBalancer[name]
if !ok {
err = fmt.Errorf("Not found %s balancer", name)
return
}
fmt.Printf("use %s balance\n", name)
inst, err = balancer.DoBalance(insts)
return
}

mgr.go

package balance

import (
"errors"
"math/rand"
) func init() {
RegisterBalancer("random", &RandomBalance{})
} type RandomBalance struct {
} func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
if len(insts) == 0 {
err = errors.New("No instance")
return
}
lens := len(insts)
index := rand.Intn(lens)
inst = insts[index]
return
}

random.go

package balance

import (
"errors"
) func init() {
RegisterBalancer("roundrobin", &RoundRobinBalance{})
} type RoundRobinBalance struct {
curIndex int
} func (p *RoundRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
if len(insts) == 0 {
err = errors.New("No instance")
return
}
lens := len(insts)
if p.curIndex >= lens {
p.curIndex = 0
}
inst = insts[p.curIndex]
p.curIndex = (p.curIndex + 1) % lens
return
}

roundrobin.go

  • main
package main

import (
"fmt"
"go_dev/day7/example/example1/balance"
"hash/crc32"
"math/rand"
) type HashBalance struct {
} func init() {
balance.RegisterBalancer("hash", &HashBalance{})
} func (p *HashBalance) DoBalance(insts []*balance.Instance, key ...string) (inst *balance.Instance, err error) {
var defkey string = fmt.Sprintf("%d", rand.Int())
if len(key) > 0 {
// err := fmt.Errorf("hash balance must pass the hash key")
defkey = key[0]
}
lens := len(insts)
if lens == 0 {
err = fmt.Errorf("No backend instance")
return
}
crcTable := crc32.MakeTable(crc32.IEEE)
hashVal := crc32.Checksum([]byte(defkey), crcTable)
index := int(hashVal) % lens
inst = insts[index] return
}

hash.go

package main

import (
"fmt"
"go_dev/day7/example/example1/balance"
"math/rand"
"os"
"time"
) func main() {
// 定义一个空切片
// insts := main([]*balance.Instance)
var insts []*balance.Instance
for i := 0; i < 16; i++ {
host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
one := balance.NewInstance(host, 8080)
insts = append(insts, one) // 自动对空切片进行扩容
}
// 选择负载均衡算法
var balanceName = "random"
if len(os.Args) > 1 {
balanceName = os.Args[1]
}
// var balancer balance.Balancer
// var conf = "random"
// if len(os.Args) > 1 {
// conf = os.Args[1]
// }
// if conf == "random" {
// balancer = &balance.RandomBalance{} // 随机
// fmt.Println("use random balancer")
// } else if conf == "roundrobin" {
// balancer = &balance.RoundRobinBalance{} // 轮询
// fmt.Println("use roundrobin balancer")
// }
// balancer := &balance.RandomBalance{} // 随机
// balancer := &balance.RoundRobinBalance{} // 轮询 for {
inst, err := balance.DoBalance(balanceName, insts)
if err != nil {
// fmt.Println("do balance err:", err)
fmt.Fprintf(os.Stdout, "do balance error\n")
continue
}
fmt.Println(inst)
time.Sleep(time.Second)
} } // 运行
// go run go_dev/day7/example/example1/main random
// go run go_dev/day7/example/example1/main roundrobin
// go run go_dev/day7/example/example1/main hash
// 编译
// go build go_dev/day7/example/example1/main

main.go

反射

1. 反射:可以在运行时动态获取变量的相关信息

Import (“reflect”)

两个函数:

  • a. reflect.TypeOf,获取变量的类型,返回reflect.Type类型
  • b. reflect.ValueOf,获取变量的值,返回reflect.Value类型
  • c. reflect.Value.Kind,获取变量的类别,返回一个常量
  • d. reflect.Value.Interface(),转换成interface{}类型

2. reflect.Value.Kind()方法返回的常量

3. 获取变量的值:

reflect.ValueOf(x).Float()
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()

4. 通过反射的来改变变量的值

reflect.Value.SetXX相关方法,比如:
reflect.Value.SetFloat(),设置浮点数
reflect.Value.SetInt(),设置整数
reflect.Value.SetString(),设置字符串

5. 用反射操作结构体

a. reflect.Value.NumField()获取结构体中字段的个数
b. reflect.Value.Method(n).Call来调用结构体中的方法

6.案例

package main

import (
"fmt"
"reflect"
) type Student struct {
Name string
Age int
Score float32
} func test(b interface{}) {
t := reflect.TypeOf(b)
fmt.Println(t)
v := reflect.ValueOf(b)
k := v.Kind()
fmt.Println(k) iv := v.Interface()
stu, ok := iv.(Student)
if ok {
fmt.Printf("%v %T\n", stu, stu)
}
} func testInt(b interface{}) {
val := reflect.ValueOf(b)
val.Elem().SetInt(100) c := val.Elem().Int()
fmt.Printf("get value interface{} %d\n", c)
fmt.Printf("string value: %d\n", val.Elem().Int())
} func main() {
var a Student = Student{
Name: "stu1",
Age: 18,
Score: 92,
}
test(a)
var b int = 1
testInt(&b)
fmt.Println(b)
}

反射案例一

package main

import (
"encoding/json"
"fmt"
"reflect"
) type Student struct {
Name string `json:"student_name"`
Age int
Score float32
Sex string
} func (s Student) Print() {
fmt.Println("---start----")
fmt.Println(s)
fmt.Println("---end----")
} func (s Student) Set(name string, age int, score float32, sex string) { s.Name = name
s.Age = age
s.Score = score
s.Sex = sex
} func TestStruct(a interface{}) {
tye := reflect.TypeOf(a)
val := reflect.ValueOf(a)
kd := val.Kind()
if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
fmt.Println("expect struct")
return
} num := val.Elem().NumField()
val.Elem().Field(0).SetString("stu1000")
for i := 0; i < num; i++ {
fmt.Printf("%d %v\n", i, val.Elem().Field(i).Kind())
} fmt.Printf("struct has %d fields\n", num) tag := tye.Elem().Field(0).Tag.Get("json")
fmt.Printf("tag=%s\n", tag) numOfMethod := val.Elem().NumMethod()
fmt.Printf("struct has %d methods\n", numOfMethod)
var params []reflect.Value
val.Elem().Method(0).Call(params)
} func main() {
var a Student = Student{
Name: "stu01",
Age: 18,
Score: 92.8,
} result, _ := json.Marshal(a)
fmt.Println("json result:", string(result)) TestStruct(&a)
fmt.Println(a)
}

反射案例二

Go语言系列(六)- 接口和反射的更多相关文章

  1. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  2. R语言数据分析系列六

    R语言数据分析系列六 -- by comaple.zhang 上一节讲了R语言作图,本节来讲讲当你拿到一个数据集的时候怎样下手分析,数据分析的第一步.探索性数据分析. 统计量,即统计学里面关注的数据集 ...

  3. go语言之行--接口(interface)、反射(reflect)详解

    一.interface简介 interface(接口)是golang最重要的特性之一,Interface类型可以定义一组方法,但是这些不需要实现.并且interface不能包含任何变量. 简单的说: ...

  4. Go语言的接口与反射

    美女图片没啥用,就是为了好看 本文还在完善中... go总体而言是一门比较好入门的语言,许多特性都很精简易懂,但是接口与反射除外.他们真的让人头疼,不知道是自身资质问题还是怎么着,总是觉得很多书上写的 ...

  5. Go语言系列之反射

    变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指在程序运行期对程序本身进行访问和修改的能力.程序在编译时,变量 ...

  6. SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性

    原文:SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server 2008 ...

  7. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  8. java基础解析系列(六)---注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer缓存及 ...

  9. CSS 魔法系列:纯 CSS 绘制各种图形《系列六》

    我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...

  10. NeHe OpenGL教程 第二十六课:反射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

随机推荐

  1. MFC打印

    映射模式是MFC甚至SDK界面编程第1个难点.打印则是第2个难点.这2个都是历史遗留的设计缺陷.这些缺陷还不至于到bug程度,但却很难用,不易理解. MFC提供2个类来实现打印(预览),具体有CPri ...

  2. centos7防火墙导致不能访问的

    CentOS 7.0默认使用的是firewall作为防火墙,使用iptables必须重新设置一下 1.直接关闭防火墙 systemctl stop firewalld.service #停止firew ...

  3. docker容器日志收集方案(方案二 filebeat+syslog本地日志收集)

    与方案一一样都是把日志输出到本地文件系统使用filebeat进行扫描采集 不同的是输出的位置是不一样的 我们对docker进行如下设置 sudo docker service update  --lo ...

  4. 【Python使用】使用pip安装卸载Python包(含离线安装Python包)未完成???

    pip 是 Python 包管理工具,该工具提供了对Python包的查找.下载.安装.卸载的功能.Python 2.7.9 + 或 Python 3.4+ 以上版本都自带 pip 工具. pip使用( ...

  5. asp.net 客户端请求到响应的整个过程

    出处:https://www.cnblogs.com/Joans/archive/2012/02/08/2342887.html 疑惑?从客户端发出一个请求,请求到达服务端如何和IIS关联起来?IIS ...

  6. w3m 使用总结

    安装 sudo apt install w3m终端 w3m www.baidu.com 即可打开w3m是个开放源代码的命令行下面的网页浏览器.一般的linux系统都会自带这个工具,可以通过它在命令行下 ...

  7. wangEditor的使用

    wangEditor的使用 第一步,将其下载,并引入项目中. 第二步,引入js <script type="text/javascript" src="/plugi ...

  8. UVALive - 3523 - Knights of the Round Table

    Problem  UVALive - 3523 - Knights of the Round Table Time Limit: 4500 mSec Problem Description Input ...

  9. Linux实战教学笔记49:Zabbix监控平台3.2.4(一)搭建部署与概述

    https://www.cnblogs.com/chensiqiqi/p/9162986.html 一,Zabbix架构 zabbix 是一个基于 WEB 界面的提供分布式系统监视以及网络监视功能的企 ...

  10. Autoware(2)—加载地图数据

    选择Point cloud.Ref选择.autoware/.data/map/pointcloud_map/里面的全选 点Point cloud加载 vector Map和TF同理