Go by Example : Struct Embedding
Next example: Generics .
by Mark McGranaghan and Eli Bendersky | source | license
- Data Types in Go
- Go Keywords
- Go Control Flow
- Go Functions
- GoLang Structures
- GoLang Arrays
- GoLang Strings
- GoLang Pointers
- GoLang Interface
- GoLang Concurrency
Embedded Structures in Golang
In the Go programming language, Embedded Structures are a way to reuse a struct’s fields without having to inherit from it. It allows you to include the fields and methods of an existing struct into a new struct. The new struct can add additional fields and methods to those it inherits.
type outer struct { inner struct { field1 string field2 int } }
Explanation: This program defines two structs – Address and Person. The Person struct includes the Address struct. In the main function, a Person named “John Doe” is created with an address of “New York, NY”. The program then prints out the person’s name, city, and state. Because the Address struct is included in the Person struct, we can access the person’s city and state directly from the Person struct using dot notation. The program simply creates a person object with an address and prints out some of their details.
Explanation: This program creates two structs – Author and HR. The HR struct includes the Author struct. An instance of the HR struct is created with a value of the Author field set to “Dhruv”, “IT”, and 2024. The program then prints the message “Details of Author” followed by the result variable value. The output shows the Author fields inside the HR struct with curly braces.
Similar Reads
- Go Language
Please Login to comment...
Improve your coding skills with practice.
What kind of Experience do you want to share?
Embedding in Go: Part 3 - interfaces in structs
This post is part 3 in a series describing the kinds of embedding Go supports:
- Structs in structs ( part 1 )
- Interfaces in interfaces ( part 2 )
- Interfaces in structs (this part)
Embedding interfaces in structs
At first sight, this is the most confusing embedding supported in Go. It's not immediately clear what embedding an interface in a struct means. In this post we'll work through this technique slowly and present several real-world examples. At the end, you'll see that the underlying mechanics are pretty simple and the technique is useful in various scenarios.
Let's start with a simple synthetic example:
Fooer is an interface and Container embeds it. Recall from part 1 that an embedding in a struct promotes the embedded struct's methods to the embedding struct. It works similarly for embedded interfaces; we can visualize it as if Container had a forwarding method like this:
But what does cont.Fooer refer to? Well, it's just any object that implements the Fooer interface. Where does this object come from? It is assigned to the Fooer field of Container when the container is initialized, or later. Here's an example:
Now we can do:
This will print sink: TheRealFoo Foo .
What's going on? Notice how the Container is initialized; the embedded Fooer field gets assigned a value of type TheRealFoo . We can only assign values that implement the Fooer interface to this field - any other value will be rejected by the compiler. Since the Fooer interface is embedded in Container , its methods are promoted to be Container 's methods, which makes Container implement the Fooer interface as well! This is why we can pass a Container to sink at all; without the embedding, sink(co) would not compile because co wouldn't implement Fooer .
You may wonder what happens if the embedded Fooer field of Container is not initialized; this is a great question! What happens is pretty much what you'd expect - the field retains its default value, which in the case of an interface is nil . So this code:
Would result in a runtime error: invalid memory address or nil pointer dereference .
This pretty much covers how embedding interfaces in structs works. What remains is the even more important question of - why would we need this? The following examples will present several use cases from the standard library, but I want to begin with one coming from elsewhere and demonstrating what is - in my opinion - the most important use of this technique in client code.
Example: interface wrapper
This example is courtesy of GitHub user valyala , taken from this comment .
Suppose we want to have a socket connection with some additional functionality, like counting the total number of bytes read from it. We can define the following struct:
StatsConn now implements the net.Conn interface and can be used anywhere a net.Conn is expected. When a StatsConn is initialized with a proper value implementing net.Conn for the embedded field, it "inherits" all the methods of that value; the key insight is, though, that we can intercept any method we wish, leaving all the others intact. For our purpose in this example, we'd like to intercept the Read method and record the number of bytes read:
To users of StatsConn , this change is transparent; we can still call Read on it and it will do what we expect (due to delegating to sc.Conn.Read ), but it will also do additional bookkeeping.
As shown in the previous section, it's critical to initialize a StatsConn properly; for example:
Here net.Dial returns a value that implements net.Conn , so we can use that to initialize the embedded field of StatsConn .
We can now pass our sconn to any function that expects a net.Conn argument, e.g:
And later we can access its BytesRead field to get the total.
This is an example of wrapping an interface. We created a new type that implements an existing interface, but reused an embedded value to implement most of the functionality. We could implement this without embedding by having an explicit conn field like this:
And then writing forwarding methods for each method in the net.Conn interface, e.g.:
However, the net.Conn interface has 8 methods. Writing forwarding methods for all of them is tedious and unnecessary. Embedding the interface gives us all these forwarding methods for free, and we can override just the ones we need.
Example: sort.Reverse
A classical example of embedding an interface in a struct in the Go standard library is sort.Reverse . The usage of this function is often confounding to Go newbies, because it's not at all clear how it's supposed to work.
Let's start with a simpler example of sorting in Go, by sorting an integer slice.
This prints [1 2 3 4 5 8 9] . How does it work? The sort.Sort function takes an argument implementing the sort.Interface interface, which is defined as:
If we have a type we'd like to sort with sort.Sort , we'll have to implement this interface; for simple types like an int slice, the standard library provides convenience types like sort.IntSlice that take our value and implement the sort.Interface methods on it. So far so good.
So how does sort.Reverse work? By cleverly employing an interface embedded in a struct. The sort package has this (unexported) type to help with the task:
By this point it should be clear what this does; reverse implements sort.Interface by means of embedding it (as long as it's initialized with a value implementing the interface), and it intercepts a single method from that interface - Less . It then delegates it to the Less of the embedded value, but inverts the order of arguments. This Less actually compares element in reverse, which will make the sort work in reverse.
To complete the solution, the sort.Reverse function is simply:
And now we can do:
Which prints [9 8 5 4 3 2 1] . The key point to understand here is that calling sort.Reverse itself does not sort or reverse anything. It can be seen as a higher order function: it produces a value that wraps the interface given to it and adjusts its functionality. The call to sort.Sort is where the sorting happens.
Example: context.WithValue
The context package has a function called WithValue :
It "returns a copy of parent in which the value associated with key is val ." Let's see how it works under the hood.
Ignoring error checking, WithValue basically boils down to:
Where valueCtx is:
Here it is - a struct embedding an interface again. valueCtx now implements the Context interface and is free to intercept any of Context 's 4 methods. It intercepts Value :
And leaves the rest of the methods untouched.
Example: degrading capability with a more restricted interface
This technique is quite advanced, but it's used in many places throughout the standard library. That said, I don't expect it is commonly needed in client code so if you're a Go newbie and you don't get it on the first read, don't worry too much. Get back to it after you gain some more Go experience.
Let's start by talking about the io.ReaderFrom interface:
This interface is implemented by types that can meaningfully read data from an io.Reader . For example, the os.File type implements this interface and reads the data from the reader into the open file it ( os.File ) represents. Let's see how it does it:
It first attempts to read from r using the readFrom method, which is OS specific. On Linux, for example, it uses the copy_file_range syscall for very fast copying between two files, directly in the kernel.
readFrom returns a boolean saying whether it succeeded ( handled ). If not, ReadFrom attempts to do a "generic" operation using genericReadFrom , which is implemented as:
It uses io.Copy to copy from r to f , so far so good. But what is this onlyWriter wrapper?
Interesting. So this is our - familiar by now - trick of an interface embedded in a struct. But if we search around in the file we won't find any methods defined on onlyWriter , so it doesn't intercept anything. Why is it needed then?
To understand why, we should look at what io.Copy does. Its code is long so I won't reproduce it fully here; but the key part to notice is that if its destination implements io.ReaderFrom , it will invoke ReadFrom . But this brings us back in a circle, since we ended up in io.Copy when File.ReadFrom was called. This causes an infinite recursion!
Now it starts to become clear why onlyWriter is needed. By wrapping f in the call to io.Copy , what io.Copy gets is not a type that implements io.ReaderFrom , but only a type that implements io.Writer . It will then call the Write method of our File and avoid the infinite recursion trap of ReadFrom .
As I've mentioned earlier, this technique is on the advanced side. I felt it's important to highlight because it represents a markedly different use of the "embed interface in struct" tool, and it's pervasively used throughout the standard library.
The usage in File is a good one because it gives onlyWriter an explicitly named type, which helps understand what it does. Some code in the standard library eschews this self-documenting pattern and uses an anonymous struct. For example, in the tar package it's done with:
For comments, please send me an email .
DEV Community
Posted on Jan 6, 2023
Most sophisticated embedding pattern in Go: embedded interface within a struct
From my point of view, this pattern is one of many explanatory examples, but should be learnt by heart until completely comprehended . It's like writing an explicit callback for another callback in JavaScript – takes time to make a final "Gotcha!"
runnable code example on REPLIT
Open shell instance and type: go run embedded-interf2--advanced.go # <= this might change in the future so don't think hard, think smart !
Related articles :
understand-interfaces
interfaces-in-structs: practical side of such embedding
If you found any typo, or think you can suggest a better solution, please leave a comment below . Stay tuned !
Top comments (0)
Templates let you quickly answer FAQs or store snippets for re-use.
Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .
Hide child comments as well
For further actions, you may consider blocking this person and/or reporting abuse
Why Web Workers Depend on JavaScript ??
Shafayet Hossain - Oct 20
AI and Machine Learning in Web Development: Driving a New Generation of Intelligent Web Applications
Okoye Ndidiamaka - Oct 7
Mystical Palm Reader AI
ehernandezvilla - Oct 13
AI-Driven Cloud Resource Optimization: A Developer’s Guide
Ethan Lee - Oct 7
We're a place where coders share, stay up-to-date and grow their careers.
Struct embedding as implicit composition
May 22, 2020 11:26 +0100 · 678 words · 4 minutes read beginner coding-design golang java programming.
In programming, the principle “don’t repeat yourself”, DRY for short, recommends that we try to reuse the same implementation where possible. In this post, I will cover what it’s like to do it in golang through struct embedding and my personal thoughts on that pattern.
Golang struct embedding
One common way of code reuse is inheritance. In Java, we can do this by implementing a method on the parent class, then subclasses will inherit this implementation.
Golang does not support inheritance, but we can get pretty far with composition, in particular, with struct embedding. Composition is adding a field to a struct that references another struct. When the field is anonymous, it is called struct embedding. The effect of this is that fields and functions on the embedded struct is exposed to the outer struct as well.
Note that even though the embedding is anonymous, it has to be explicitly specified when initializing the struct
Assuming the parent has the following receiver function, the child will also have access to the implementation.
This means if Parent satisfy some interface Doer , then the structs embedding Parent would also satisfy the interface Doer .
Downsides: readability
This comes at a cost of readability if both Parent and Child have some field name conflicts and it’s not immediately obvious which struct it belongs to.
For this reason, I often prefer that the reference is explicit when referring to the parent field.
Warning: Not true sub typing
The definition of subtype says that if A is a subtype of B, then wherever we expect a B, we can use a A.
Struct embedding does not satisfy this.
Note: If Parent is an exported field, then we can still do process(Child{}.Parent) but this isn’t as “nice”.
Proxy pattern - explicit composition
As seen above, we trade off possible readability issues for the convenience of not redefining all the interface that the parent expose.
Suppose our goal is to make sure Child , which we conceptually think of as subtype of Parent , also satisfy an interface Doer , which Parent already implements, then we can implement the interface by calling Parent ’s implementation
The downside here is that even though the implementation is trivial, it is still boilerplate that doesn’t say much. Code can get a bit repetitive when we start to proxy more than a handful of functions.
Consider the scenario where the parent now have 5 functions, and we have 5 children that are logical subtypes of the parent, using this pattern, we would have implemented 25 proxy functions that does not do anything other than to call the parent. Imaging having to add on another function to the parent that requires proxying, we now have to add 5 more boilerplate.
IMAGES
VIDEO
COMMENTS
I have a RegistrationRequest struct: type RegistrationRequest struct { Email *string Email2 *string Username *string Password *string Name string } Where Email2 is the email value entered again to verify that what the user entered is correct. I also have a User struct:
Go supports embedding of structs and interfaces to express a more seamless composition of types. This is not to be confused with //go:embed which is a go directive introduced in Go version 1.16+ to embed files and folders into the application binary.
There are three kinds of embedding in Go: Structs in structs (this part) Interfaces in interfaces (part 2) Interfaces in structs (part 3) Embedding structs in structs. We'll start with a simple example demonstrating the embedding of a struct in another struct:
One of the most powerful features of Go is the ability to embed structs and interfaces to create a more seamless composition of types. In this article, we will explore the concept of struct embedding in Go, how it works, and its use cases.
I have the following struct which contains a net/http.Request: type MyRequest struct {. http.Request. PathParams map[string]string. } Now I want to initialize the anonymous inner struct http.Request in the following function: func New(origRequest *http.Request, pathParams map[string]string) *MyRequest {. req := new(MyRequest)
In the Go programming language, Embedded Structures are a way to reuse a struct’s fields without having to inherit from it. It allows you to include the fields and methods of an existing struct into a new struct.
Embedding interfaces in structs. At first sight, this is the most confusing embedding supported in Go. It's not immediately clear what embedding an interface in a struct means. In this post we'll work through this technique slowly and present several real-world examples.
Struct embedding is a powerful feature in Go that allows us to include one struct type into another, thereby promoting its methods and fields.
Open shell instance and type: go run embedded-interf2--advanced.go # <= this might change in the future so don't think hard, think smart ! Related articles : understand-interfaces. interfaces-in-structs: practical side of such embedding.
Golang does not support inheritance, but we can get pretty far with composition, in particular, with struct embedding. Composition is adding a field to a struct that references another struct. When the field is anonymous, it is called struct embedding.