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) fmt.Printf("\n\n") 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ıkçı", 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("") 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) }