Interfaces
Interfaces are an important part of Go’s type system and program design.
1. Duck typing
Duck typing
If a bird walks, swims, and quacks like a duck, treat it as a duck.
This focuses on available behavior rather than internal structure.
A type satisfies an interface when its method set contains all the interface’s methods; a value of that type can then be used through the interface.
2. Declaring an interface
Use type and interface in the following form:
type 接口名 interface{
方法名1(参数列表) 返回值列表
方法名2(参数列表) 返回值列表
...
}
Example:
type Duck interface{
Gaga()
Walk()
Swimming()
}
type pskDuck struct{
legs int
}
func (pd *pskDuck) Gaga(){
fmt.Println("嘎嘎嘎")
}
func (pd *pskDuck) Walk(){
fmt.Println("走")
}
func (pd *pskDuck) Swimming(){
fmt.Println("游泳")
}
func main(){
var duck Duck = &pskDuck{}
duck.Gaga()
duck.Walk()
duck.Swimming()
}
3. Implementing multiple interfaces
Keep interfaces small and focused; many useful interfaces contain a single method.
type Duck interface{
Gaga()
}
type Duck2 interface{
Walk()
}
type Duck3 interface{
Swimming()
}
type pskDuck struct{}
、
func (pd *pskDuck) Gaga(){
fmt.Println("嘎嘎嘎")
}
func (pd *pskDuck) Walk(){
fmt.Println("走")
}
func (pd *pskDuck) Swimming(){
fmt.Println("游泳")
}
func main(){
var duck Duck = &pskDuck{}
var duck2 Duck2 = &pskDuck{}
}
In this example, pskDuck satisfies Duck, Duck2, and Duck3. main declares a Duck variable, and a pskDuck value can be assigned because it implements all of Duck’s methods.
Interfaces can also be used for struct fields and function parameters.
They offer flexible ways to organize behavior.
Decoupling code
One type can satisfy several interfaces, and several types can satisfy the same interface.
……
4. Interfaces and dynamic values
Type assertions
For example, a calculator that adds values:
func add(a, b interface{}) interface{}{
switch a.(type){
case int:
ai, _ := a.(int)
bi, _ := b.(int)
return ai + bi
case int32:
ai, _ := a.(int32)
bi, _ := b.(int32)
return ai + bi
case float32:
ai, _ := a.(float32)
bi, _ := b.(float32)
return ai + bi
//……
default:
return 0
}
}
func main(){
fmt.Println(add(1, 2))
fmt.Println(add(1, 3))
fmt.Println(add(1.0, 2.0))
}
5. Embedded interfaces
Embedding interfaces lets us combine method requirements and reuse definitions.
type MyWriter interface{
Write(string)
}
type MyReader interface{
Reader() string
}
type MyReaderWriter interface{
MyReader
MyWriter
ReadWriter()
}
type SreadWriter struct{}
func (srw *SreadWriter) Read(){
fmt.Println("read")
}
func (srw *SreadWriter) Write(){
fmt.Println("write")
}
func (srw *SreadWriter) ReadWriter(){
fmt.Println("readWriter")
}
func main(){
var mrw MyReaderWriter = &SreadWriter{}
mrw.Read()
}
6. A common slice conversion mistake
A slice can be passed as an interface value. The restriction illustrated here is different: []T cannot be directly converted to []interface{} merely because each T satisfies the interface. Convert the elements individually when that representation is needed.
func mPrint(data ... interface{}){
for _, value := range data{
fmt.Println(value)
}
}
func main(){
//这样是支持的
var data = []interface{}{
"aaaaa",
19,
1800.00,
}
mPrint(data...)
}