GoLang Notes
Go standard library (selected) interfaces
Go packages
- https://pkg.go.dev
- https://github.com/golang/go/wiki/Projects
Struct initialisation
var product = new(Product) OR var product = Product{}
Compositions
field promotion - If the enclosing type has a field same as a field of embedded type’s field, then the direct access to the attribute will render enclosing type’s field value. Fields and Methods can be promoted to the enclosing type from embedded type
type Boat struct {
*Product
Capacity int
Motorized bool
}
type Product struct {
Name, Category string
price float64
}
func (p *Product)Price(tax) float64{
return p.price + p.price*tax
}
Name
can be accessed by either boat.Product.Name
and boat.Name
boat.Price(0.2)
or boat.Product.Price(0.2)
- Both are equivalent.
type Product struct {
Name, Category string
Price float64
}
type ProductGroup []*Product
func (group ProductGroup) CalcTotal() float64{
...
}
A receiver function can only be defined on type
, so a receiver function here
can’t be defined on []*Product
, thus we need to create alias type
-
ProductGroup
so that it can have a receiver method.
Interface
Since GoLang doesn’t support inheritance, it provides interface
to provide similar functionality.
Adapter to execute a synchornous function asynchronously
calcTax := func(price float64) float64 {
return price*0.2
}
resultChannel := make(chan float64)
go func(price float64, c chan float64) {
c <- calcTax(price)
}(275, resultChannel) // Price and channel passed as arguments
The for
loop and range
on chan ranges over just channel, it doesn’t return index
// Range over channel just returns the message on channel
testProductChannel := make(chan *Product, 5)
go nonBlockingSendEnumerateProducts(chan<- *Product(testProductChannel))
time.Sleep(time.Second)
for p := range testProductChannel {
fmt.Println("Received", p.Name)
}
// Range over slice has index and object from slice
slice := []string{"Chandan", "Alok", "Ruby", "Darsh", "Tithi", "Sheenu"}
for i, str := range slice {
fmt.Println(i, str)
}
NOTE: goroutine functions usually doesn’t have return value, instead it sends the message via channel
Slice
When defining a slice on a struct, the elements can be direct definition of struct as below:
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type Product struct {
Name string
}
var pSlice = []*Product{
{"Chandan"},
{"Alok"},
}
var vSlice = []Product{
{"Chandan"},
{"Alok"},
}
func main() {
for _, p := range pSlice {
fmt.Println(p.Name)
}
for _, p := range vSlice {
fmt.Println(p.Name)
}
}
Error interface
Go provides a predefined interface named error that provides one way to create own error types(structs)
type error interface {
Error()
}
This inteface requires errors to define a method named Error, which returns a string Example:
type CategoryError struct {
requestedCategory string
}
func(category *CategoryError) Error() string {
return "ERROR: " + category + "is invalid"
}
// NOTE: As CategoryError is a struct implementing Error interface
// Thus &CategoryError{requestedCategory: category} will print the error message
// i.e. returned string of Error() function
func main() {
// This is equivalent to fmt.Println(string)
// where string is returned value of Error() function above
fmt.Println(&CategoryError{requestedCategory: category})
}
// =============== ANOTHER example
package errors_test
import (
"fmt"
"time"
)
// MyError is an error implementation that includes a time and message.
type MyError struct {
When time.Time
What string
}
func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.When, e.What)
}
func oops() error {
return MyError{
time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
"the file system has gone away",
}
}
func Example() {
if err := oops(); err != nil {
fmt.Println(err)
}
// Output: 1989-03-15 22:30:00 +0000 UTC: the file system has gone away
}
%v specifierType of object:
- Use
%T
to get the Go type of a value - As we get the class of objects in other OOP languages - Use
%#v
format that could be used to re-create the value in Go code file - Use
%v
default format of the value - Use
%+v
includes the field name
pattern, compileErr := regexp.Compile("[A-z]oat")
question := "Is that a goat?"
if compileErr == nil {
fmt.Println(pattern.MatchString(question))
fmt.Printf("Type: %T\n", pattern)
fmt.Printf("Go code: %#v\n", pattern)
fmt.Printf("Recreate: %+v\n", pattern)
} else {
fmt.Println("Error: ", compileErr)
}
// Output
true
Type: *regexp.Regexp
Go code: ®exp.Regexp{expr:"[A-z]oat", prog:(*syntax.Prog)(0x14000072240), onepass:(*regexp.onePassProg)(nil), numSubexp:0, maxBitStateLen:43690, subexpNames:[]string{""}, prefix:"", prefixBytes:[]uint8(nil), prefixRune:0, prefixEnd:0x0, mpool:0, matchcap:2, prefixComplete:false, cond:0x0, minInputLen:4, longest:false}
Recreate: [A-z]oat
Format string for a struct
User Stringer
interface from fmt
package
type Stringer interface {
String() string
}
This is a sapling 🌱 in my digital garden 🏡.