Golang and inheritance

后端 未结 2 397
有刺的猬
有刺的猬 2020-12-24 12:56

I want to provide a base struct with methods in my library that can be \'extended\'.

The methods of this base struct rely on methods from the extending struct. This

2条回答
  •  孤城傲影
    2020-12-24 13:50

    As mentioned in people's comments, Go encourages composition over inheritance.

    To address your question about reducing code duplication, you would want to use embedding.

    Using the example from Effective Go linked above, you start with very narrow interfaces that only do a few things:

    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    

    Then you can either compose interfaces together into another interface:

    // ReadWriter is the interface that combines the Reader and Writer interfaces.
    type ReadWriter interface {
        Reader
        Writer
    }
    

    It works similarly for structs, where you can compose structs that implement Reader and Writer together in another struct:

    type MyReader struct {}
    func (r *MyReader) Read(p []byte) (n int, err error) {
        // Implements Reader interface.
    }
    type MyWriter struct {}
    func (w *MyWriter) Write(p []byte) (n int, err error) {
        // Implements Writer interface.
    }
    
    // MyReadWriter stores pointers to a MyReader and a MyWriter.
    // It implements ReadWriter.
    type MyReadWriter struct {
        *MyReader
        *MyWriter
    }
    

    Basically, anything that implements a Reader or a Writer can be reused by composing them together in a struct, and that outer struct will automatically implement the ReadWriter interface.

    This is basically doing Dependency Injection, and it's super useful for testing too.

    Example from the struct code above:

    func (rw *MyReadWriter) DoCrazyStuff() {
        data := []byte{}
        // Do stuff...
        rw.Read(data)
        rw.Write(data)
        // You get the idea...
    }
    
    func main() {
        rw := &MyReadWriter{&MyReader{}, &MyWriter{}}
        rw.DoCrazyStuff()
    }
    

    One thing to point out that's slightly different from other languages' composition paradigm is that the MyReadWriter struct can now act as both a Reader and a Writer. That's why in DoCrazyStuff() we do rw.Read(data) instead of rw.Reader.Read(data).

    UPDATE: Fixed incorrect example.

提交回复
热议问题