当前位置: 动力学知识库 > 问答 > 编程问答 >

Golang String method for interface type

问题描述:

I am solving the problems for the book The Go Programming Language,

and in exercise 7.13 it is required to add a String method to an interface.

Is this possible to add a String() method to an interface? Because the data type is not known until runtime.

网友答案:

Adding a method to an interface just means to include that method in the method set defined by the interface type.

For example this is an interface:

type Fooer interface {
    Foo()
}

It has one method: Foo(). To add the String() method to this interface:

type Fooer interface {
    Foo()
    String() string
}

Done. We have added the String() method to this interface.

This has the consequence that if a concrete type wants to implement this Fooer interface, previously it was enough to have just a Foo() method. Now it also has to have a String() method.

Also note that in Go implementing interfaces is implicit. There is no declaration of intent. A type implicitly satisfies an interface if it has all the methods of the interface.

A concrete type may or may not have a String() method, independently from our Fooer interface. The concrete type may not even know about our Fooer interface, and it doesn't need to.

Here's a concrete type implementating this Fooer interface:

type fooerImpl int

func (f fooerImpl) Foo() {
    fmt.Printf("Foo() called, I'm %d\n", int(f))
}

func (f fooerImpl) String() string {
    return fmt.Sprintf("Foo[%d]", int(f))
}

Testing it:

var f Fooer = fooerImpl(3)
f.Foo()
fmt.Println(f.String())
fmt.Println(f)

Output (try it on the Go Playground):

Foo() called, I'm 3
Foo[3]
Foo[3]

Consequences of adding a method to an interface

If you arbitrarily add a new method to an interface, it may cause certain existing concrete types which previously implemented the interface to not implement it anymore (due to lack of the newly added method).

If these existing concrete types were used as instances of the interface, they will cause a compile-time error and will not work until you add the missing new method. For example if we remove the fooerImpl.String() method from the above example, the code var f Fooer = fooerImpl(3) results in compile-time error:

cannot use fooerImpl(3) (type fooerImpl) as type Fooer in assignment:
    fooerImpl does not implement Fooer (missing String method)

If the existing concrete types were not used as instances of the interface directly, but e.g. they were passed around wrapped in the empty interface interface{} and type assertion was used to extract a value of the interface, those type assertions will not hold anymore. The "simple" form of type assertion x.(T) will result in a runtime panic, the special form v, ok := x.(T) will return nil and false.

For example using the above fooerImpl type without the String() method:

var f0 interface{} = fooerImpl(3)
f := f0.(Fooer)

Results in runtime panic:

panic: interface conversion: main.fooerImpl is not main.Fooer: missing method String

And using the special form of type conversion:

if f, ok := f0.(Fooer); ok {
    f.Foo()
} else {
    fmt.Println("Not instance of Fooer!", f)
}

Results in:

Not instance of Fooer! <nil>

If by any chance the existing concrete type already had a method which you have just added to the interface and it has the same signature (same parameter and return types), then that's cool, the concrete type will "continue" to implement the new interface too. If the signatures do not match (e.g. the existing method has different return type), then it will not satisfy the interface and it's the same as not having a method with the same name.

分享给朋友:
您可能感兴趣的文章:
随机阅读: