216 lines
5 KiB
Go
216 lines
5 KiB
Go
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("<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)
|
||
}
|