package main import ( "fmt" // "math" "reflect" ) type Vertex struct { X, Y float64 } func (v Vertex) Twice() (float64, float64) { // Twice method has a receiver of type Vertex named v return (v.X) * 2, (v.Y * 2) } func Twice2(v Vertex) (float64, float64) { return (v.X) * 2, (v.Y * 2) } //func (f float64) Abs() float64 { // ERROR: cannot define new methods on non-local type float64 //return 1.4} type MyFloat float64 // First declare type //Then use this type in a method func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } func (v Vertex) Mult(f float64) { v.X *= f v.Y *= f fmt.Printf("%p\n", &v) } func (v *Vertex) Mult2(f float64) { v.X *= f v.Y *= f fmt.Printf("%p (address of pointer: %p)\n", v, &v) } func Mult3(v *Vertex, f float64) { v.X *= f v.Y *= f fmt.Printf("%p (address of pointer: %p)\n", v, &v) } func Mult4(v Vertex, f float64) { v.X *= f v.Y *= f fmt.Printf("%p\n", &v) } func main() { fmt.Println("Go doest not have classes, but you can define methods on types") fmt.Println("A method is a function with a special receiver argument") fmt.Println("The Receiver appears between func keyword and the method name") v := Vertex{10, 15} fmt.Println(v.Twice()) fmt.Println("You can make this with also using regular functions:") fmt.Println(Twice2(v)) fmt.Printf("\n\n") fmt.Println("You cannot declare a method with a receiver whose type is defined in another package. Because of that you also cannot use types like int or float64") fmt.Println("You can declare a new type for solving this") fmt.Printf("\n") var x MyFloat = 12 fmt.Println(x, reflect.TypeOf(x), reflect.TypeOf(x).Kind()) f := MyFloat(-123.34) // same as `var f MyFloat = 123.34` fmt.Println(f.Abs()) fmt.Printf("\n\n") fmt.Println("Also pointers can be used as receivers in methods") v2 := Vertex{12, 13} fmt.Printf("V2: %p\n", &v2) v2.Mult(12) fmt.Println(v2) fmt.Printf("\n") v3 := Vertex{12, 13} fmt.Printf("V3: %p\n", &v3) v3.Mult2(12) // `(&v3).Mult2(12)` // ! ACTUALLY SAME THING fmt.Println(v3) p := &v3 fmt.Printf("V3: %p, P: %p, (address of p pointer: %p)\n", &v3, p, &p) p.Mult2(2) fmt.Println(v3, p) // BOTH CHANGED fmt.Printf("\n") fmt.Println("Pointers also can be used with functions but we should pass the variables with ampersant") v4 := Vertex{12, 13} fmt.Printf("V4: %p\n", &v4) // Mult3(v4, 4) // ERROR Mult3(&v4, 12) fmt.Println(v4) fmt.Printf("\n") fmt.Println("Also we can declare our first value as pointer for avoid using ampersant") p2 := &Vertex{12, 13} fmt.Printf("P2: %p, (address of p2 pointer: %p)\n", p2, &p2) p2.Mult2(2) Mult3(p2, 6) fmt.Println(p2) fmt.Printf("\n\n") fmt.Println("We couldn't use addresses while function requires a normal value in functions. But while using as methods pointers renders it values") myVar1 := Vertex{1, 2} Mult4(myVar1, 2) // OK // Mult4(&myVar1, 2) // Compile ERRORr fmt.Println(myVar1) myPoint1 := &myVar1 myVar1.Mult(2) //OK myPoint1.Mult(2) //ALSO OK, interpreted as (*myPoint1).Mult(2) // SAME WITH (*myPoint1).Mult(2) fmt.Println(myVar1) fmt.Println(myPoint1) fmt.Printf("\n\n") fmt.Println("Using pointer receivers provides more efficent way, bcs there is no copy process") fmt.Println("We should avoid using values and pointer receivers together") }