Development & AI | Alper Akgun
In this followup blog, I will learn a bit more about go. I study through the examples at use https://gobyexample.com
Go supports pointers.
package main
import "fmt"
func val42(ival int) {
ival = 42
}
func ptr42(iptr *int) {
*iptr = 42
}
func main() {
i := 1
fmt.Println("start:", i)
val42(i)
fmt.Println("Zero val:", i)
ptr42(&i)
fmt.Println("Zero ptr:", i)
fmt.Println("Pointer:", &i)
}
Structs are collection of typed fields. They enabled object oriented programming.
package main
import "fmt"
type student struct {
name string
age int
grade int
}
func newStudent(name string) *student {
p := student{name: name}
p.age = 42
p.grade = 95
return &p
}
func main() {
fmt.Println(student{"Bob", 12})
fmt.Println(student{name: "Alice", age: 32, grade: 100})
fmt.Println(&student{name: "Ann", age: 42})
fmt.Println(newStudent("John"))
s := student{name: "Steve", age: 5, grade: 90}
fmt.Println(s.name)
sp := &s
fmt.Println(sp.age)
sp.age = 51
fmt.Println(sp.age)
circle := struct {
name string
isFilled bool
}{
"MyCircle",
true,
}
fmt.Println(circle)
}
Methods can be defined on struct types.
package main
import "fmt"
type ellipse struct {
width, height int
}
func (r *ellipse) area() int {
return r.width * r.height * 3.14159
}
func main() {
r := ellipse{width: 10, height: 5}
fmt.Println("area: ", r.area())
rp := &r
fmt.Println("area: ", rp.area())
}
Interfaces allow methods to be typed and added to structs.
package main
package main
import (
"fmt"
"math"
)
type shape interface {
area() float64
perim() float64
}
type rectangle struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rectangle) area() float64 {
return r.width * r.height
}
func (r rectangle) perim() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func measure(g shape) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rectangle{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
measure(c)
}
Embedding structs and interfaces allow type composition.
package main
import "fmt"
type construction struct {
num int
}
func (b construction) describe() string {
return fmt.Sprintf("construction %v", b.num)
}
type house struct {
construction
str string
}
func main() {
co := house{
construction: construction{
num: 1,
},
str: "some name",
}
fmt.Printf("construction={num: %v, str: %v}\n", co.num, co.str)
fmt.Println("also num:", co.construction.num)
fmt.Println("describe:", co.describe())
type describer interface {
describe() string
}
var d describer = co
fmt.Println("describer:", d.describe())
}
Generics allow making types polymorhic, similar to C++ templates.
package main
import "fmt"
func KeyMapper[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
type List[T any] struct {
head, tail *element[T]
}
type element[T any] struct {
next *element[T]
val T
}
func (lst *List[T]) Push(v T) {
if lst.tail == nil {
lst.head = &element[T]{val: v}
lst.tail = lst.head
} else {
lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next
}
}
func (lst *List[T]) GetAll() []T {
var elems []T
for e := lst.head; e != nil; e = e.next {
elems = append(elems, e.val)
}
return elems
}
func main() {
var m = map[int]string{1: "2", 3: "9", 4: "16"}
fmt.Println("keys:", KeyMapper(m))
_ = KeyMapper[int, string](m)
lst := List[int]{}
lst.Push(12)
lst.Push(29)
fmt.Println("list:", lst.GetAll())
}
Go has explicitly returned error handling, unlike exception mechanisms in other languages.
package main
import (
"errors"
"fmt"
)
func fnot42(arg int) (int, error) {
if arg == 42 {
return -1, errors.New("can't work with 42")
}
return arg + 3, nil
}
type argError struct {
arg int
prob string
}
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func fplus3(arg int) (int, error) {
if arg == 42 {
return -1, &argError{arg, "can't work with it"}
}
return arg + 3, nil
}
func main() {
for _, i := range []int{7, 42} {
if r, e := fnot42(i); e != nil {
fmt.Println("fnot42 failed:", e)
} else {
fmt.Println("fnot42 worked:", r)
}
}
for _, i := range []int{7, 42} {
if r, e := fplus3(i); e != nil {
fmt.Println("fplus3 failed:", e)
} else {
fmt.Println("fplus3 worked:", r)
}
}
_, e := fplus3(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}