接口

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. SQL SERVER-查询爆破sa密码的主机

    drop table if exists #sql create table #sql ( Logdatae ), processinfo ), [text] varchar(max) ) go IN ...

  2. UGUI合批原理笔记

    可以通过Frame debugger查看每个drawcall绘制了哪些东西 UGUI源码下载地址:https://bitbucket.org/Unity-Technologies/ui/downloa ...

  3. python--继承--方法的重写---和父类的扩展

    1.方法的重写 父类的方法不能满足子类的需要,可以对方法重写 具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并实现 重写之后只会对子类的方法调用,而不会调用父类封装的方法 2.对父类方法进 ...

  4. 关于SNMP的MIB文件的语法简述

    源地址:https://blog.csdn.net/carechere/article/details/51236184 SNMP协议的MIB文件的常见宏定义的描述: 对MIB文件中一些常见的宏定义的 ...

  5. Python基础——5模块

    使用模块 ‘the first line is zhushi’ _author_ = ‘syz’ import sys def test(): args = sys.argv if len(args) ...

  6. Jquery自动补全插件的使用

    1.引入css和js  <script src="js/jquery-ui.min.js"></script> <link href="cs ...

  7. mn

    http://image.uczzd.cn/10129986679866437816.jpg?id=0&from=export https://www.cnblogs.com/ityoukno ...

  8. Spark-RDD之Partition源码分析

    概要 Spark RDD主要由Dependency.Partition.Partitioner组成,Partition是其中之一.一份待处理的原始数据会被按照相应的逻辑(例如jdbc和hdfs的spl ...

  9. 前端面试回顾---javascript的面向对象

    转:https://segmentfault.com/a/1190000011061136 前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用 ...

  10. Node、TS、Koa学习笔记

    这样定义可以轻松拿到gender属性 这样定义,函数内显示没有gender 这种方法能得到gender但是函数内部没有gender 这种方式能到gender 但是在函数里施symbel属性,外部不能访 ...