The conflict problem of implicit interface in go language
The go language uses an implicit interface, which can be used as an interface as long as the definition of the interface is satisfied.
such as the built-in error
interface:
type error struct {Error() string}
There are many advantages to implicit interfaces. But I personally think that the main point is not to draw the ancestors of the eight Generations of inheritance diagram (loose coupling).
However, an implicit interface can cause conflicting problems.
To put it simply, I also want to define my own MyError
interface, which also has a Error() string
method:
type MyError struct {Error() string}
But I want MyError
interfaces and error
interfaces to be of different types (cannot be converted to each other).
Of course, the MyError
interface and interface are equivalent in the Go language, and it error
is difficult to prohibit the conversion between them.
We can generally MyError
add a unique empty method to the interface to avoid this problem:
type MyError struct {Error() stringAssertMyError()}
Method AssertMyError
is just to differentiate error
the interface, no other use.
This is protobuf in Proto. Message uses the method:
// Message is implemented by generated protocol buffer messages.type Message interface {Reset()String() stringProtoMessage()}
Each type generated Message
has a special ProtoMessage
null method, which specifically corresponds to the proto.Message
interface.
Of course, there is a danger of conflict if there is just another interface that has a ProtoMessage
method.
The extreme approach is to randomly generate a special method name, such as a UUID with a unique name.
However, the public name still has the risk of being maliciously covered by others (unlikely in practice).
A more rigorous approach is to define the method name that distinguishes the interface as a private method. For example testing.TB
:
type TB interface {Error(args ...interface{})Errorf(format string, args ...interface{})Fail()FailNow()Failed() boolFatal(args ...interface{})Fatalf(format string, args ...interface{})Log(args ...interface{})Logf(format string, args ...interface{})Skip(args ...interface{})SkipNow()Skipf(format string, args ...interface{})Skipped() bool// A private method to prevent users implementing the// interface and so future additions to it will not// violate Go 1 compatibility.private()}
private
It is not just a private method, but it must be the type of the testing
method defined inside the package private()
to match this interface!
The testing.TB
interface is therefore globally unique and does not present an equivalent, interchangeable interface.
The uniqueness of the interface is now testing.TB
guaranteed, but how is this interface implemented externally ( private()
testing
defined within the package)?
We can testing.TB
inherit this method from the interface private()
:
package mainimport ("fmt""testing")type TB struct {testing.TB}func (p *TB) Fatal(args ...interface{}) {fmt.Println("TB.Fatal disabled!")}func main() {var tb testing.TB = new(TB)tb.Fatal("Hello, playground")}
Play Address: http://play.golang.org/p/tFB0fLwq9q
The above code simulates an explicit interface, and the testing.TB
interface never has to worry about conflicting risks.
Of course, the above code has a problem with overuse techniques, which is contradictory to the simple programming philosophy of Go language.
The conflict problem of implicit interface in go language