简体   繁体   中英

golang function type inheritance?

Consider this example in Go language:

type I interface {
    get() string
}

type S struct {}
func (s *S) get() string {
    return "here!"
}
var sSupplier = func() *S {
    return &S{}
}

func foo(supplier func () I) {
    i := supplier()
    println(i)
}

func main() {
    foo(sSupplier) // compile error, type mismatch
}

Type S inherit interface I . But apparently type func () *S does not inherit func () I , so I cannot call foo with sSupplier in place of the supplier function. Is there a way to fix it without forcing sSupplier to return type I ?

In java you can use generics to do something like <T extends I> void foo(Supplier<T> supplier) {...} then call foo(sSupplier); with Supplier<S> sSupplier type. I'm not sure if similar approach is possible in go?

If you think for a bit about what generics do for you, they are really a way to ask the compiler to compile, on the spot, an anonymous wrapper function or lambda or whatever is needed to map from some concrete type. That is, given something like (I'll use C++ syntax here rather than Java as I'm much more familiar with C++):

template<T>
void f(T obj) {
    // do stuff with the object
}

you're telling the compiler that when it sees f(int_value) it should build a function f that takes an int , and when it sees f(struct S) it should build a function f that takes a struct S , and so on. (This is a bit more natural in Java than it is in C++'s C underpinnings since Java does the whole argument-matching thing to decide which of these various f functions to call.)

In effect, instead of writing the actual function, you write a template —hence the C++ keyword—that the compiler can use to, at compile time, produce the function you really wanted. Since Go lacks generics, it lacks this sort of template-expansion trick.

That leaves you with several obvious alternatives, though. One is exemplified by go:generate (see, eg, Explain go generate in this example ). In this particularly simple case, though, you can just write the expansion yourself in line:

foo(func() I { return sSupplier() })

See a more complete example on the Go playground . I replacd your println(i) with fmt.Printf("%#v\\n", i) to print the interface object's value in a slightly more useful form.

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