In today’s article, I will introduce to you what is Go embedding and how it can be used in Go. Golang is not an OOP programming language. However, some of the benefits of object orientation can be applied to go structs (similar to Class), interface, and method are all available to be embedded. The embedding type will be used to use the “inherit” property in Go.
Embedded Type is declaring a type in another type but not declaring a name, a field without declaring a name is also known as an embedded field.
Embedding structs in Golang
Here is an example of embedding a struct in another one:
type Author struct {
AuthorName string
AuthorAge int
}
type Book struct {
Title string
Author // Embedded field
}
In the above example, if we name the Author field as usual, we will
have a nested struct, and if we use an Embedded field, we can
consider the Book struct to have all the fields of the Author struct
(duplicate field names are not allowed). The Book struct above will
equivalent to:
type Book struct {
Title string
Content string
AuthorName string
AuthorAge int
}
We will be able to use both Book and Author struct without having to re-declare duplicate fields.
When retrieving data can also be obtained directly without going through a nested truct, for example, get the author’s name instead of book.Author.AuthorName, then we just need to book.AuthorName. See the full example here:
package main
import "fmt"
type Author struct {
AuthorName string
AuthorAge int
}
type Book struct {
Title string
Author // Embedded field
}
func main() {
book1 := Book{
Title: "Book1",
Author: Author{
AuthorName: "author1",
AuthorAge: 19,
},
}
fmt.Println(book1)
fmt.Println(book1.AuthorAge)
fmt.Println(book1.Author.AuthorAge)
}
Output:
{Book1 {author1 19}}
19
19
Embedding methods in Golang
It also works well to embed structs with methods. Suppose we have access to this method for Author struct:
func (author Author) SayHello() string {
return fmt.Sprintf("I am %v. Hello GoLinuxCloud members!", author.AuthorName)
}
Now that Author struct has this method, we can call it on instances of Book as if it did too:
package main
import "fmt"
type Author struct {
AuthorName string
AuthorAge int
}
type Book struct {
Title string
Author // Embedded field
}
func main() {
book1 := Book{
Title: "Book1",
Author: Author{
AuthorName: "author1",
AuthorAge: 19,
},
}
author1 := Author{
AuthorName: "author2",
AuthorAge: 22,
}
fmt.Println(author1.SayHello())
fmt.Println(book1.SayHello())
}
func (author Author) SayHello() string {
return fmt.Sprintf("I am %v. Hello GoLinuxCloud members!", author.AuthorName)
}
Output:
I am author2. Hello GoLinuxCloud members!
I am author1. Hello GoLinuxCloud members!
When book1.SayHello() is call, the actual logic is the below method will be called. Calling SayHell() on the Book struct has a similar result to our original one, which embeds.
func (bk Book) SayHello() string {
return bk.Author.SayHello()
}
This example also highlights a key detail in the behavior of methods on embedded fields: regardless of the embedding struct it is called through, Author’s SayHello() always receives a Author (the leftmost (…) in the method description). In other languages that support inheritance, such as Python and C++, inherited methods receive a reference to the subclass via which they are called. This is a significant distinction between embedding in Go and traditional inheritance.
Embedding interfaces in Golang
The interface is a group of method signatures that can be used to construct variables in the Go programming language. As far as we are aware, the Go language does not enable inheritance, but the Go interface does. An interface can incorporate other interfaces or the method signatures of other interfaces in it when embedding. You can embed any number of interfaces in a single interface. And when an interface, embed other interfaces in it if we made any changes in the methods of the interfaces.
type interface1 interface {
Method1()
}
type interface2 interface {
Method2()
}
type embedded_interface interface {
interface1
interface2
}
OR
type interface1 interface {
Method1()
}
type interface2 interface {
Method2()
}
type embedded_interface interface {
Method1()
Method2()
}
Here is an example of embedding interface into another interface:
package main
import "fmt"
// Interface 1
type inteface1 interface {
AthorDetails()
}
// Interface 2
type inteface2 interface {
CustomDetails()
}
type embedded interface {
inteface1
inteface2
}
// struct
type Author struct {
AuthorName string
AuthorAge int
}
// Implementing method of the interface 1
func (a Author) AthorDetails() {
fmt.Printf("I am %v, i am %v years old. Hello GoLinuxCloud members!\n", a.AuthorName, a.AuthorAge)
}
// Implementing method of the interface 2
func (a Author) CustomDetails() {
fmt.Printf("This is a customized message! I am %v, i am %v years old.\n", a.AuthorName, a.AuthorAge)
}
func main() {
author := Author{
AuthorName: "author1",
AuthorAge: 22,
}
// Accessing the methods of the interface 1 and 2
var f embedded = author
f.AthorDetails()
f.CustomDetails()
}
Output:
I am author1, i am 22 years old. Hello GoLinuxCloud members!
This is a customized message! I am author1, i am 22 years old.
Embedding Files in Golang
This feature was added in Go 1.16 that allows you toembed static
assetsinto Go binaries. The allowed data types for keeping an embedded
file arestring,[]byte, andembed.FS. This means that a Go binary
may contain a file that you do not have to manually download when you
execute the Go binary! The presented utility embeds two different files
that it can retrieve based onthe given command-line argument.
package main
import (
_ "embed"
"fmt"
"os"
)
//go:embed static/firefox.png
var f1 []byte
//go:embed static/file1.txt
var f2 string
func writeToFile(s []byte, path string) error {
fd, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer fd.Close()
n, err := fd.Write(s)
if err != nil {
return err
}
fmt.Printf("wrote %d bytes\n", n)
return nil
}
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Println("Print select 1|2")
return
}
fmt.Println("f1:", len(f1), "f2:", len(f2))
switch arguments[1] {
case "1":
filename := "/tmp/out.png"
err := writeToFile(f1, filename)
if err != nil {
fmt.Println(err)
return
}
case "2":
fmt.Print(f2)
default:
fmt.Println("Not a valid option!")
}
}
Explanation:
You need theembedpackage in order to embed any files in your Go
binaries. As theembedpackage is not directly used, you need to
put_ in front of it so that the Go compiler won’t complain.
You need to begin a line with//go:embed, which denotes a Go comment
but is treated in a special way, followed by the path to the file you
want to embed. In this case we embed static/file1.txt, which is a binary
file. The next line should define the variable that is going to hold the
data of the embedded file, which in this case is a byte slice named f1
using a byte slice is recommended for binary files because we are going
to directly use that byte slice to save that binary file.
//go:embed static/firefox.png
var f1 []byte
//go:embed static/file1.txt
var f2 string
In this case we save thecontents of a plain text file, which
isstatic/textfile, in astringvariable namedf2.
ThewriteToFile()function is used for storing a byte slice into a
file and is a helper function that can be used in other cases as well.
Theswitchblock
is responsible for returning the desired file to the user in the case of
static/textfile, the file contents are printed on the screen. For the
binary file, we decided to store it as /tmp/out.png.
Next we execute the binary:
$ go run main.go 2
f1: 32441 f2: 6
hello
$ go run main.go 1
f1: 32441 f2: 6
wrote 32441 bytes
$ ll /tmp/out.png
-rw-r--r-- 1 root root 32441 Nov 20 14:39 /tmp/out.png
$ md5sum /tmp/out.png static/firefox.png
db0cad7c310dcd7673d976699293f08d /tmp/out.png
db0cad7c310dcd7673d976699293f08d static/firefox.png
Using the embedding functionality, we can create a utility that embeds
its own source code and prints it on screen when it gets executed! This
is a fun way of using embedded files. The source code of main.go is
the following:
package main
import (
_ "embed"
"fmt"
)
//go:embed main.go
var src string
func main() {
fmt.Print(src)
}
Output
$ go run main.go
package main
import (
_ "embed"
"fmt"
)
//go:embed main.go
var src string
func main() {
fmt.Print(src)
As before, the file that is being embedded is defined in
the//go:embed line. Running main.go prints the aforementioned code
on screen.
Summary
Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation byembedding types within a struct or interface. With the explained examples below, hope you can have a better understanding of embedding in Golang.

![Golang Embedding Examples [Tutorial]](/golang-embedding/golang-embedding.jpg)
