简体   繁体   中英

How to pass interface to struct on golang

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

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() // runtime error here
                fmt.Printf("num %v\n", f.num)
        }
    }
}

func main()(){
    var foo Foo
    foo.num = 2
    FooChan <- &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() ?

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

type IImplementPersonMethod struct {}


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

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 (
    "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() // runtime error here
                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)
}

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 := <-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 (
    "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)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM