在Go语言中使用接口的用法

huangapple go评论87阅读模式
英文:

Usage of interface in Go

问题

我想通过一个简单的示例来了解Go语言中接口类型的使用方式。

我阅读了网络文档,但是我不太明白。

英文:

I would like to understand the interface type with a simple example of it's use in Go (Language).

I read the web documentation, but I don't get it.

答案1

得分: 49

go接口的背后思想是鸭子类型。简单来说就是:如果你看起来像一只鸭子,叫起来像一只鸭子,那么你就是一只鸭子。这意味着如果你的对象实现了所有鸭子的特征,那么将其作为鸭子使用应该没有问题。下面是一个例子:

package main

import (
	"fmt"
)

type Walker interface {
	Walk() string
}

type Human string
type Dog string

func (human Human) Walk() string { //人是一个行走者
	return "我是一个人,我走了!"
}

func (dog Dog) Walk() string { //狗是一个行走者
	return "我是一只狗,我走了!"
}

//让行走者行走
func MakeWalk(w Walker) {
	fmt.Println(w.Walk())
}

func main() {
	var human Human
	var dog Dog
	MakeWalk(human)
	MakeWalk(dog)
}

在这里,Human是一个WalkerDog也是一个Walker。为什么呢?因为它们都...嗯...会走路。它们都实现了Walk() string函数。所以你可以在它们上面执行MakeWalk

当你希望不同类型以相同的方式行为时,这非常有用。一个实际的例子是文件类型对象(套接字、文件对象)- 你需要在它们上面有一个写入和读取函数。然后你可以以相同的方式使用写入和读取,而不考虑它们的类型-这很酷。

英文:

The idea behind go interfaces is duck typing. Which simply translates into: If you look like a duck and quack like a duck then you are a duck. Meaning that if your object implements all duck's features then there should be no problem using it as a duck. Here is an example:

package main

import (
	"fmt"
)

type Walker interface {
	Walk() string
}

type Human string
type Dog string

func (human Human) Walk() string { //A human is a walker
	return "I'm a man and I walked!"
}

func (dog Dog) Walk() string { //A dog is a walker
	return "I'm a dog and I walked!"
}

//Make a walker walk
func MakeWalk(w Walker) {
	fmt.Println(w.Walk())
}

func main() {
	var human Human
	var dog Dog
	MakeWalk(human)
	MakeWalk(dog)
}

Here a Human is a Walker and a Dog is a Walker. Why? Because they both.. well... Walk. They both implement the Walk () string function. So this is why you can execute MakeWalk on them.

This is very helpful when you want different types to behave in the same manner. A practical example would be file type objects (sockets, file objects) - you need a Write and a Read function on all of them. Then you can use Write and Read in the same fashion independent of their type - which is cool.

答案2

得分: 2

另一个工作示例展示了接口和结构之间的交互

package main

import "fmt"

type Info interface {
    Noofchar() int
    Increment()
}

type Testinfo struct {
    noofchar int
}

func (x *Testinfo) Noofchar() int {
    return x.noofchar
}
func (x *Testinfo) Increment() {
    x.noofchar++
}

func main(){
    var t Info = &Testinfo{noofchar:1}
    fmt.Println("字符数量",t.Noofchar())
    t.Increment()
    fmt.Println("字符数量",t.Noofchar())
}
英文:

Another working example showing the interaction between an interface and a structure

package main

import "fmt"

type Info interface {
Noofchar() int
Increment()
}

type Testinfo struct {
noofchar int     
}

func (x *Testinfo) Noofchar() int {
return x.noofchar
}
func (x *Testinfo) Increment() {
x.noofchar++
}

func main(){
var t Info = &Testinfo{noofchar:1}
fmt.Println("No of char ",t.Noofchar())
t.Increment()
fmt.Println("No of char ",t.Noofchar())
}

答案3

得分: 0

为了补充@AlexPlugaru在这里和@NickCraig-Wood在https://stackoverflow.com/a/18854285/12817546给出的出色答案。

package main

import . "fmt"

func main() {
    cat("Bird").Eat()      // Bird
    eater.Eat(cat("Milk")) // Milk
    Break(cat("Fish"))     // Fish
    Lunch().Eat()          // Mice
    Tea(true)           // Bird
}

type cat string
type eater interface{ Eat() }

func (c cat) Eat()  { Println(c) }
func Break(e eater) { e.Eat() }
func Lunch() eater  { return cat("Mice") }
func Tea(b bool) {
    if b {
        cat("Bird").Eat()
    }
}

结构体或任何其他具体类型上的方法是静态解析的。参见cat("Bird").Eat()eater.Eat(cat("Milk"))。唯一具有动态分派方法的方式是通过接口。参见Break(cat("Fish"))Lunch().Eat(),http://www.golangbr.org/doc/faq#How_do_I_get_dynamic_dispatch_of_methods。

Tea(true)在不使用接口的情况下动态调用方法。参见https://talks.golang.org/2014/taste.slide#19。但是,接口-通过设计和约定-鼓励我们编写可组合的代码。参见https://talks.golang.org/2014/go4gophers.slide#21。

结果是:简单的组件通过小接口连接在一起。参见https://talks.golang.org/2012/chat.slide#5。最好有许多小而简单的东西,而不是一个大而复杂的东西。参见https://talks.golang.org/2014/go4gophers.slide#24。

您还可以将任何内容隐藏在私有包中,只公开特定类型、接口和工厂函数。参见Break(cat("Fish"))Lunch().Eat(),https://code.tutsplus.com/tutorials/lets-go-object-oriented-programming-in-golang--cms-26540

英文:

To add to the excellent answer by @AlexPlugaru here and by @NickCraig-Wood at https://stackoverflow.com/a/18854285/12817546.

package main

import . "fmt"

func main() {
	cat("Bird").Eat()      // Bird
	eater.Eat(cat("Milk")) // Milk
	Break(cat("Fish"))     // Fish
	Lunch().Eat()          // Mice
	Tea(true)           // Bird
}

type cat string
type eater interface{ Eat() }

func (c cat) Eat()  { Println(c) }
func Break(e eater) { e.Eat() }
func Lunch() eater  { return cat("Mice") }
func Tea(b bool) {
	if b {
		cat("Bird").Eat()
	}
}

Methods on a struct or any other concrete type are resolved statically. See cat("Bird").Eat() and eater.Eat(cat("Milk")). The only way to have dynamically dispatched methods is through an interface. See Break(cat("Fish")) and Lunch().Eat(), http://www.golangbr.org/doc/faq#How_do_I_get_dynamic_dispatch_of_methods.

Tea(true) calls a method dynamically without using an interface. See https://talks.golang.org/2014/taste.slide#19. But interfaces—by design and convention—encourage us to write composable code. See https://talks.golang.org/2014/go4gophers.slide#21.

The result: simple pieces connected by small interfaces. See https://talks.golang.org/2012/chat.slide#5. Better to have many small simple things than one big complex thing. See https://talks.golang.org/2014/go4gophers.slide#24.

You can also hide anything in a private package and just expose specific types, interfaces, and factory functions. See Break(cat("Fish")) and Lunch().Eat(), https://code.tutsplus.com/tutorials/lets-go-object-oriented-programming-in-golang--cms-26540

答案4

得分: 0

在这个例子中,我使用接口来演示如何在Golang中实现多态。

package main

import (
"fmt"
"math"
)

func main() {
rect := Rectangle{20, 50}
cir := Circle{2}

//根据传入的对象,在getArea方法中改变行为,这就是多态。
fmt.Println("矩形的面积 =", getArea(rect))
fmt.Println("圆的面积 =", getArea(cir))

}

//接口Shape有一个area方法
type Shape interface {
area() float64
}

//使用结构体创建Rectangle和Circle类型
type Rectangle struct {
height float64
width float64
}

type Circle struct {
radius float64
}

//实现结构体的area方法
func (r Rectangle) area() float64 {
return r.height * r.width
}

func (c Circle) area() float64 {
return math.Pi * math.Pow(c.radius, 2)
}

//将接口作为参数传递,可以计算任何指定类型的形状
//所有的结构体都因为接口而联系在一起。
func getArea(shape Shape) float64 {
return shape.area()
}

英文:

In this example, I'm using the interface to demonstrate how to achieve polymorphism in Golang.

package main 


import(
	"fmt"
	"math"
)

func main(){
	rect := Rectangle{20,50}
	cir := Circle{2}
	
	//According to object you passed in getArea method, 
	// it will change the behaviour and that is called Polymorphism.
	fmt.Println("Area of Rectangle =",getArea(rect))
	fmt.Println("Area of Circle =",getArea(cir))
	
}

//Interface Shape with one area method
type Shape interface{
	 area() float64
}

//Creating Rectangle and Circle type using struct 
type Rectangle struct{
	height float64
	width float64
}

type Circle struct{
	radius float64
}

//Receiver function, which implements struct's area methods
func(r Rectangle) area() float64{
	return r.height * r.width
}

func(c Circle) area() float64{
	return math.Pi * math.Pow(c.radius,2)
}

//passing interface as arguments, which can calculate shape of any mentioned type
//All the struct are tied together because of the Interface.
func getArea(shape Shape) float64{
	return shape.area()
}

huangapple
  • 本文由 发表于 2011年8月12日 23:41:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/7042640.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定