Interfaces and Embedding in Golang (Go)
1. Interfaces in Go:
1.1. What are Interfaces?
In Go, an interface is a type that specifies a set of method signatures. When a concrete type provides definitions for all the methods in an interface, it is said to implement the interface.
1.2. Defining Interfaces:
You define an interface using the type
keyword followed by the interface name and the interface
keyword:
type Writer interface {
Write([]byte) (int, error)
}
1.3. Significance in Go's Type System:
Interfaces in Go allow you to:
Define behavior that types should fulfill.
Enable polymorphic behavior. You can write functions and methods that accept interface types, and then pass values of any concrete type that satisfies the interface.
Provide a way to define contracts. If a type implements an interface, it guarantees certain methods with defined signatures are present in the type.
1.4. Interface Values:
Interface values can hold any value that implements the specified methods. An interface value has two components: a value and a concrete type. When we call a method on an interface value, the method of its underlying type is executed.
var w Writer
w = os.Stdout
w.Write([]byte("Hello, Go!\n"))
In the above example, os.Stdout
implements the Writer
interface, so we can assign it to the w
variable. When we call w.Write
, it calls os.Stdout.Write
.
2. Embedding in Go:
2.1. What is Embedding?
Embedding allows one struct type to include another struct, inheriting the fields and methods of the embedded type. It is Go's mechanism to achieve composition over traditional inheritance.
2.2. How to Embed:
To embed a type, you declare a field in the struct without a field name, just the type:
type Address struct {
Street, City, State string
}
type Person struct {
Name string
Address
}
p := Person{
Name: "Alice",
Address: Address{"123 Main St", "Anytown", "CA"},
}
fmt.Println(p.Street) // Output: 123 Main St
In the above code, Person
embeds Address
. This means that a Person
not only has a Name
but also has Street
, City
, and State
due to the embedded Address
.
2.3. Inheritance-like Behavior:
Embedding provides a way to "inherit" methods. If the embedded type has methods, the embedding type will have those methods too, provided it doesn't define its own methods with the same name.
func (a Address) FullAddress() string {
return a.Street + ", " + a.City + ", " + a.State
}
// Even though Person doesn't define FullAddress, it gains the method through embedding Address.
address := p.FullAddress()
However, Go doesn't support classical inheritance where you can extend and override base class methods. Instead, Go promotes composition over inheritance, making systems easier to understand and maintain.
To summarize:
Interfaces in Go allow types to adhere to contracts and enable polymorphism.
Embedding allows structs to inherit fields and methods from other structs, giving a mechanism for composition over classical inheritance.
Thank you for reading. I encourage you to follow me on Twitter where I regularly share content about JavaScript and React, as well as contribute to open-source projects and learning golang. I am currently seeking a remote job or internship.
Twitter: https://twitter.com/Diwakar_766
GitHub: https://github.com/DIWAKARKASHYAP
Portfolio: https://diwakar-portfolio.vercel.app/