go-learning/3methods/interfaces.go

217 lines
5 KiB
Go
Raw Permalink Normal View History

2023-07-23 13:03:01 +03:00
package main
import (
"fmt"
"math"
"reflect"
)
type Abser interface {
Abs() float64
}
type I interface {
M()
}
type I2 interface {
C()
}
type Vertex struct {
X, Y float64
}
type Vertex2 struct {
X, Y float64
}
type T struct {
S string
}
type MyFloat float64
func main() {
fmt.Println("An interface type is defined as a set of method signatures")
var f Abser = MyFloat(1.2)
var va Abser = &Vertex{3, 4}
var v Abser = Vertex2{3, 4}
// var v Abser = Vertex{3, 4} // ERROR, Same Vertex type not work because interface recognize them as same type
fmt.Println(f.Abs()) // goes to `func (f MyFloat) Abs() float64 {`
fmt.Println(va.Abs()) // goes to `func (v *Vertex) Abs() float64 {`
fmt.Println(v.Abs()) // goes to `func (v Vertex2) Abs() float64 {`
fmt.Println(reflect.TypeOf(f), reflect.TypeOf(f).Kind())
fmt.Println(reflect.TypeOf(va), reflect.TypeOf(va).Kind())
fmt.Println(reflect.TypeOf(v), reflect.TypeOf(v).Kind())
/*
TODO No need to interfaces ?
```
f := MyFloat(1.2)
va := &Vertex{3, 4}
v := Vertex2{3, 4}
```
Also this code block works even with Abser interface removed ?
---
Also in this example: https://github.com/Furkan-Gulsen/turkce-go-egitimi#interfaces
There is no need to interfaces, just remove the interface and use methods normally as circle.area(), square.area() ...
What is our motivation to use Interfaces ???
*/
// TODO what's the point! https://go.dev/tour/methods/10
// TODO In this example describe function uses Interface as argument. And this prevents multiple describe function. Is it a use case for interfacse (https://go.dev/tour/methods/11)
// TODO LOOK FOR HEAD-FIRST-GO EXAMPLES
// LINK https://www.digitalocean.com/community/tutorials/how-to-use-interfaces-in-go
// LINK https://duncanleung.com/understand-go-golang-interfaces/
// LINK https://research.swtch.com/interfaces
// TODO Understand interfaces more !
fmt.Printf("\n\n")
fmt.Println("If the concrete value inside the interface itself is nil, the method will be called with a nil receiver")
var i I
var t *T
i = t
describe(i)
i.M()
i = &T{"hello"}
describe(i)
i.M()
fmt.Printf("\n")
fmt.Println("A nil interface value holds neither value nor concrete type")
var i2 I2
describe2(i2)
// i2.C() // panic: runtime error: invalid memory address or nil pointer dereference
fmt.Printf("\n\n")
fmt.Println("The interface type that specifies zero methods is known as the empty interface:")
var i3 interface{}
describe3(i3)
fmt.Println("An empty interface may hold values of any type")
i3 = 43
describe3(i3)
i3 = "hello"
describe3(i3)
fmt.Println("Empty interfaces are used by code that handles values of unknown type")
fmt.Printf("\n\n")
fmt.Println(" A type assertion provides access to an interface value's underlying concrete value. Can be used with t:=i.(T)")
var i4 interface{} = "hello"
s := i4.(string)
fmt.Println(s)
fmt.Println("You can also test if type is true with two variable. This also prevents panic")
s, ok := i4.(string)
fmt.Println(s, ok)
f2, ok := i4.(float64)
fmt.Println(f2, ok) // 0 false
// f3 := i4.(float64) // panic: interface conversion: interface {} is string, not float64
// fmt.Println(f3)
2023-07-24 14:39:38 +03:00
fmt.Printf("\n\n")
2023-07-23 13:03:01 +03:00
fmt.Println("You can also use interfaces for getting a variable as argument and then deciding type of this variable. var.(type) returns interfaces type. And then you can check different types with switch-case")
somevar(61)
somevar("hello")
fmt.Printf("\n\n")
fmt.Println("One of the most ubiquitous interfaces is Stringer defined by the fmt package. A Stringer is a type that can describe itself as a string. he fmt package (and many others) look for this interface to print values.")
/*
type Stringer interface {
String() string
}
*/
fmt.Println("This means you can change output style with String() method for a type")
myVarA := Person{"Aliberk Sandıı", 50}
myVarB := Person{"Burak", 100}
myVarC := Person2{"Kemal", 150}
fmt.Println(myVarA, myVarB, myVarC)
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s + %d, ", p.Name, p.Age)
}
type Person2 struct {
Name string
Age int
}
func (p Person2) String() string {
return fmt.Sprintf("%s ! %d", p.Name, p.Age)
}
func somevar(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("INT: %v, %T\n", v, v)
case string:
fmt.Printf("STRING: %v, %T\n", v, v)
default:
fmt.Printf("OTHER: %v, %T\n", v, v)
}
// fmt.Println( i.(type) ) // Can't be used outside of switches!
}
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v Vertex2) Abs() float64 {
return math.Sqrt(v.X*v.X+v.Y*v.Y) + 10
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
func describe2(i I2) {
fmt.Printf("(%v, %T)\n", i, i)
}
func describe3(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}