“An interface, which is something that can do something. Including the empty interface, which is something that can do nothing, which is everything, because everything can do nothing, or at least nothing.” - Brad Fitzpatrick
type IntSlice []int and attach a method to this named user-declared type, but you can’t attach a method to []int directlyStringer interface - this defines a method String() that can be used to stringify the receiving thingtype Stringer interface {
String() string
}
fmt.Printf - it will check if the thing it needs to print satisfies the Stringer interface (is a stringer), and if so just copies the output of the String() method to its outputOutputTo function that accepts any type that implements the Write([]byte) method, meaning we can use any thing that has that method rather than a specific implementationtype ReadWriter interface {
Reader
Writer
}
ReadWriter must implement the Read and Write methodstype Bigger struct {
otherpackage.Big // Struct composition to be explored later
}
func (b Bigger) SomeMethod() {
}
type Host struct {
Hostname string
Port int
}
type SimpleURI struct {
Host
Scheme string
Path string
}
func main() {
s := SimpleURI{
Host: other.Host{Hostname: "google.com", Port: 8080},
Scheme: "https",
Path: "/search",
}
fmt.Println(s.Hostname, s.Scheme) // See how the Host has been promoted
}
SimpleURI structure would have the fields in the Host struct promoted to it’s levelHost type are also promoted to the SimpleURI type, this is the most powerful part of compositiontype Thing struct {
Field string
}
func (t *Thing) bruh() {
fmt.Println(t.Field)
}
// Would also be valid with a value receiver method
// func (t Thing) bruh() {
// fmt.Println(t.Field)
// }
type Thing2 struct {
*Thing
Field2 string
}
func main() {
t := Thing2{&Thing{"Hello"}, "world"}
t.bruh() // Method call here is valid
}
type Interface interface {
// The length of the collection
Len() int
// Says whether the element at index i is less than the element at index j
Less(i, j int) bool
// Swaps the element at index i with the element at index j in the collection
Swap(i, j int)
}
sort.Sort function can take in any Interface conforming collection type and sort it in placetype Component struct {
Name string
Weight int
}
type Components []Component
func (c Components) Len() int { return len(c) }
func (c Components) Swap() { c[i], c[j] = c[j], c[i] }
Component, and we want to make Components sortableComponents with the Less function as follows:func (c Components) Less(i, j int) {
// LT rather than the less than symbol because Jekyll
return c[i].Weight LT c[j].Weight
}
Components can be sorted by weight by defaulttype ByName struct{ Components }
func (bn ByName) Less(i, j int) bool {
return bn.Components[i].Name LT bn.Components[j].Name
}
type ByWeight struct{ Components }
func (bw ByWeight) Less(i,j int) bool {
return bn.Components[i].Weight LT bn.Components[j].Weight
}
ByName and ByWeight conform to sort.Interface through composition (since Components has the Len and Swap methods defined for it), but they then specialise the Less method to be a specific sorting strategyreverse unexported struct in sort is used to sort something in reverse ordertype reverse struct {
Interface // It just embeds sort.Interface
}
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i) // Note swapped arguments for reverse sorting
}
func Reverse(data Interface) Interface {
return &reverse{data}
}
Less method on reverse is flipped
sort.Reverse is defined that returns a sort.Interface that has the reverse implementation of Lessnil useful// The nil / zero value of this struct is ready to use since a nil slice can be appended to
type StringStack struct {
data []string
}
func (s *StringStack) Push(x string) {
s.data = append(s.data, x)
}
func (s *StringStack) Pop() string {
l := len(s.data)
if l == 0 {
panic("pop from empty stack")
}
t := s.data[l-1]
s.data = s.data[:l-1]
return t
}
data field inside the StringStack struct so that a client can’t see the implementation detailstype IntList struct {
Value int
Tail *IntList
}
func (list *IntList) Sum() int {
if list == nil {
return 0
}
return list.Value + list.Tail.Sum()
}
v := T{} you can of course call value receivers on it directly, however you can also call pointer receivers on it. The compiler will implicitly add an (&v).PointerMethod()v := &T{}, you can of course call pointer receiver methods on it directly, however Go will also implicitly add a dereference when you call a value receiver method (*v).PointerMethod()T is all the value receiver methods of T*T is all the value and pointer receiver methods of Ttype Thing struct{}
func (t Thing) ValMethod() {}
func (t *Thing) PointerMethod() {}
type IVal interface { ValMethod() }
type IPtr interface { PointerMethod() }
func main() {
var t Thing
var iVal IVal
var iPtr IPtr
iVal = t // Valid
iVal = &t // Valid
iPtr = t // Not valid, since the value t doesn't have the pointer method PointerMethod in it's method set
iPtr = &t // Valid
}