Error in user YAML: (<unknown>): found character that cannot start any token while scanning for the next token at line 5 column 1
---
title: go-basic-接口
copyright: true
date: 2019-12-12 14:43:47
tags:
- go
- go-basic
- go-basic-接口
categories:
- go
description:
---
所谓接口,就是合约======ο(=•ω<=)ρ⌒☆=======================
//来个栗子
package fmt
//只要实现Wirter接口,都可以调用Fprintf()
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf) //p.buf这个buf就是[]byte
p.free()
return
}
func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
// Sprintf formats according to a format specifier and returns the resulting string.
func Sprintf(format string, a ...interface{}) string {
..........
return s
}
package io
type Wirter interface{
Write(p []byte)(n int,err error)
}
package io
type Reader interface{
Read(p []byte) (n int, err error)
}
type Closer interface{
Close() error
}
一个类型如果实现了一个接口所有的方法,就实现了这个接口
这里Intset就实现了Stringer接口
//Intset int的集合
type Intset struct {
words []uint64
}
//fmt.Stringer
type Stringer interface {
String() string
}
//String 返回intset的string
func (s *Intset) String() string {
var buf bytes.Buffer
buf.WriteByte('{')
for i, word := range s.words {
if word == 0 {
continue
}
for j := 0; j < 64; j++ {
if word&(1<<uint(j)) != 0 {
if buf.Len() > len("}") {
buf.WriteByte('}')
}
fmt.Fprintf(&buf, "%d", 64*i+j)
}
}
}
buf.WriteByte('}')
return buf.String()
}
空接口因为没有任何要求,所以可以接受任意值
一个接口只声明没有值初始化,那么它的type和value都是nil
var w io.Writer
{% asset_img go-interface-nil.png go接口初始化 %}
初始化后,type和value将会变化
w = os.Stdout
{% asset_img go-interface-non.png go接口初始化后的type和值 %}
改变w的指向,w的type也会跟着改变
w = new(bytes.Buffer)
{% asset_img go-interface-change.png go接口值变化 %}
const debug = true
func main(){
var buf *bytes.Buffer
if debug{
buf = new(bytes.Buffer)
}
f(buf)
if debug{
.....
}
}
func f(out io.Writer){
//do something .....
if out != nil{
out.Write([]byte("hello"))
}
}
这个栗子里,如果吧debug置为false,将发生panic
为什么,看上面接口初始化,这里把nil的buf传进来后,out被初始化成type为io.Writer,而value为nil
所以if out!= nil为真,但调用out.Write是却是调用nil的value的方法
{% asset_img go-interface-func.png go函数参数为接口 %}
//do something .....
if out != nil{
out.Write([]byte("hello")) //panic:nil pointer
}
简单来说就是检查某个操作对象是否和断言的类型匹配,
- 如果T是具体类型,则检查x的动态类型是否和T相同,成功返回x的动态值,类型为T
- 如果T是接口,检查x的动态类型是否满足T,成功,不会获取到动态值,而是知晓了x满足T接口,它仍是x类型,相当于x的可获取的方法集合扩大了,有了接口T的方法
格式:x.(T), x是接口,T是类型
var w io.Writer
w = os.Stdout
f := w.(*os.File) //success, os.Stdout是file类型===ε = = (づ′▽`)づ
c := w.(*bytes.Buffer) //panic,
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // success, *io.File 实现了ReadWriter接口,里面其实就两个方法==(~o ̄3 ̄)~。。。。。
w = new(ByteCounter)
rw = w.(io.ReadWriter) //panic, *ByteCounter没有实现ReadWriter接口
//来个栗子=====n(*≧▽≦*)n====================
//io包下的Writer接口有一个Write方法,需要一个byte切片,如果直接将stirng
//转换为byte切片再写入,会生成一个临时byte切片,在数据写入后这个临时的
//byte切片就没用了,会造成内存重新分配,使得性能降低,但是大多数对于实现了
//Writer接口的类型,还实现了WriteString方法,这个方法会避免分配临时的内
//存拷贝,所以这里使用类型断言判断w是不是更加具体的StringWriter接口
type StringWriter interface {
WriteString(s string) (n int, err error)
}
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(StringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}
不要滥用接口,当有两个甚至更多类型需要实现同一个接口的时候才使用接口。
ask only for what you need.............━━( ̄ー ̄*|||━━================