How to pass interface to struct on golang

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

How to pass interface to struct on golang

问题

这是一个示例代码,我想通过一个结构体调用interface函数。

package main

import (
    "fmt"
    "time"
)

type Person interface {
    sayHello()
}

func sayHello() {
    fmt.Printf("hello\n")
}

type Foo struct {
    num    int
    person Person
}

var FooChan = make(chan *Foo, 200)

func say() {
    for {
        select {
        case f := <-FooChan:
            f.person.sayHello() // 运行时错误发生在这里
            fmt.Printf("num %v\n", f.num)
        }
    }
}

func main() {
    var foo Foo
    foo.num = 2
    FooChan <- &foo
    go say()
    time.Sleep(10 * time.Second)
}

我想通过interface调用sayHello()函数,这个Person interface可能在另一个文件中定义。当我运行它时,我得到了panic: runtime error: invalid memory address or nil pointer dereference错误。我该如何调用sayHello()函数?

英文:

Here is a sample code, I want to call interface function throw a struct

package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

type Person interface {
    sayHello()()
}

func sayHello()() {
    fmt.Printf(&quot;hello\n&quot;)
}

type Foo struct {
    num int
    person Person
}

var FooChan = make(chan *Foo, 200)

func say() () {
    for {
        select {
            case f := &lt;-FooChan:
                f.person.sayHello() // runtime error here
                fmt.Printf(&quot;num %v\n&quot;, f.num)
        }
    }
}

func main()(){
    var foo Foo
    foo.num = 2
    FooChan &lt;- &amp;foo
    go say()
    time.Sleep(10*time.Second)
}

I want to call sayHello() throw interface, this Person interface may be defined in another file. I get panic: runtime error: invalid memory address or nil pointer dereference when I run it. How can I call sayHello()?

答案1

得分: 1

你需要创建一个实现Person接口的结构体。

type IImplementPersonMethod struct {}

func (IImplementPersonMethod) sayHello() {
    fmt.Printf("hello\n")
}

然后在Foo结构体中传递这个结构体,所以你的代码应该是这样的:
(我删除了main函数上的()(),因为main是函数不需要它,否则会导致警告)

package main

import (
    "fmt"
    "time"
)

type Person interface {
    sayHello()
}

type IImplementPersonMethod struct {}

func (IImplementPersonMethod) sayHello() {
    fmt.Printf("hello\n")
}

type Foo struct {
    num int
    person Person
}

var FooChan = make(chan *Foo, 200)

func say() {
    for {
        select {
            case f := <-FooChan:
                f.person.sayHello() // 运行时错误在这里
                fmt.Printf("num %v\n", f.num)
        }
    }
}

func main(){
    var foo Foo
    foo.num = 2
    foo.person=IImplementPersonMethod{}
    FooChan <- &foo
    go say()
    time.Sleep(10*time.Second)
}
英文:

You need to create a struct that implements the interface Person.

type IImplementPersonMethod struct {}


func (IImplementPersonMethod) sayHello()() {
    fmt.Printf(&quot;hello\n&quot;)
}

Then inside the Foo, you pass this struct, so your code should be :
(i removed the ()() on main function, since main is func dont need it and it can result on a warning)

package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

type Person interface {
    sayHello()()
}

type IImplementPersonMethod struct {}


func (IImplementPersonMethod) sayHello()() {
    fmt.Printf(&quot;hello\n&quot;)
}

type Foo struct {
    num int
    person Person
}

var FooChan = make(chan *Foo, 200)

func say() () {
    for {
        select {
            case f := &lt;-FooChan:
                f.person.sayHello() // runtime error here
                fmt.Printf(&quot;num %v\n&quot;, f.num)
        }
    }
}

func main(){
    var foo Foo
    foo.num = 2
    foo.person=IImplementPersonMethod{}
    FooChan &lt;- &amp;foo
    go say()
    time.Sleep(10*time.Second)
}

答案2

得分: -1

从https://www.geeksforgeeks.org/interfaces-in-golang/:

Go语言的接口与其他语言不同。在Go语言中,接口是一种自定义类型,用于指定一个或多个方法签名的集合,接口是抽象的,因此不允许创建接口的实例。但是,您可以创建一个接口类型的变量,并且可以将该变量赋值为具有接口所需方法的具体类型值。换句话说,接口既是方法的集合,也是一种自定义类型。

因此,如果您想使通道对实现Person接口的类型进行泛型化,可能您想创建不同的类型,如农民(farmer)、医生(doctor),并且您只想调用此say方法,如下所示:

func say() {
	for {
		select {
		case f := <-FooChan:
			f.sayHello()
		}
	}
}

您只需将不同的人传递到通道中,并将获得该人类型的sayHello()方法的输出。

下面给出一个示例。希望这可以帮助您清楚Go语言接口的概念:

package main

import (
	"fmt"
	"time"
)

type Person interface {
	sayHello()
}

func (f *Farmer) sayHello() {
	fmt.Printf("hello from farmer\n")
	fmt.Printf("num %d\n", f.num)
}

type Farmer struct {
	num int
	Person
}

type Doctor struct {
	num int
	Person
}

func (f *Doctor) sayHello() {
	fmt.Printf("hello from doctor\n")
	fmt.Printf("num %d\n", f.num)
}

var FooChan = make(chan Person, 200)

func say() {
	for {
		select {
		case f := <-FooChan:
			f.sayHello()
		}
	}
}

func main() {
	foo := &Farmer{
		num: 2,
	}

	FooChan <- foo
	go say()

	foo2 := &Doctor{
		num: 1,
	}
	FooChan <- foo2

	time.Sleep(10 * time.Second)
}
英文:

From https://www.geeksforgeeks.org/interfaces-in-golang/:

> Go language interfaces are different from other languages. In Go
> language, the interface is a custom type that is used to specify a set
> of one or more method signatures and the interface is abstract, so you
> are not allowed to create an instance of the interface. But you are
> allowed to create a variable of an interface type and this variable
> can be assigned with a concrete type value that has the methods the
> interface requires. Or in other words, the interface is a collection
> of methods as well as it is a custom type.

So here if you want to make the channel generic for the types which implement the Person interface may be you want create different types like farmer, doctor and you just want to call this say method like

func say() {
	for {
		select {
		case f := &lt;-FooChan:
			f.sayHello()
		}
	}
}

And you just pass the different person in the channel and will get the output of the person type's sayHello() method's output

An example is given below. May this will help to clear you concept with golang's interface:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

type Person interface {
	sayHello()
}

func(f *Farmer) sayHello() {
	fmt.Printf(&quot;hello from farmer\n&quot;)
	fmt.Printf(&quot;num %d\n&quot;, f.num)
}

type Farmer struct {
	num int
	Person
}

type Doctor struct {
	num int
	Person
}

func(f *Doctor) sayHello() {
	fmt.Printf(&quot;hello from doctor\n&quot;)
	fmt.Printf(&quot;num %d\n&quot;, f.num)
}

var FooChan = make(chan Person, 200)

func say() {
	for {
		select {
		case f := &lt;-FooChan:
			f.sayHello()
		}
	}
}

func main(){
	foo := &amp;Farmer{
		num:    2,
	}

	FooChan &lt;- foo
	go say()

	foo2 := &amp;Doctor{
		num: 1,
	}
	FooChan &lt;- foo2

	time.Sleep(10*time.Second)
}

huangapple
  • 本文由 发表于 2021年9月14日 19:36:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/69177022.html
匿名

发表评论

匿名网友

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

确定