diff --git a/3methods/interfaces.go b/3methods/interfaces.go new file mode 100644 index 0000000..9f3153b --- /dev/null +++ b/3methods/interfaces.go @@ -0,0 +1,216 @@ +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.Println("\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) +}