diff --git a/examples/generic-database/main.go b/examples/generic-database/main.go index 3a7a38c..e959bbf 100644 --- a/examples/generic-database/main.go +++ b/examples/generic-database/main.go @@ -1,8 +1,10 @@ package main import ( + "bytes" "database/sql" "fmt" + "io" ) type IdTable interface { @@ -48,3 +50,75 @@ func Update[T IdTable](d DB, t Table[T], row T) error { func Delete[T IdTable](d DB, t Table[T], id string) error { return nil } + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + +type Transporter interface { + Transport(peopleCount int) error +} + +type Car struct { + Owner string +} + +func (c *Car) Transport(count int) error { + if count > 5 { + return fmt.Errorf(`troppe persone`) + } + + return nil +} + +type Bus struct{} + +func (c *Bus) Transport(count int) error { + if count > 40 { + return fmt.Errorf(`troppe persone`) + } + + return nil +} + +type BrokenCar struct{} + +func (c *BrokenCar) Transport(count int) error { + return fmt.Errorf(`rotta!`) +} + +func OurTrip(part1 Transporter, part2 Transporter) error { + if err := part1.Transport(3); err != nil { + return err + } + if err := part2.Transport(3); err != nil { + return err + } + + return nil +} diff --git a/slides.md b/slides.md index 5f8e411..aa2b529 100644 --- a/slides.md +++ b/slides.md @@ -142,6 +142,18 @@ func Min[T constraints.Ordered](x, y T) T { } ``` +```go +var a, b int = 0, 1 +Min[int](a, b) +``` + +```go +var a, b float32 = 3.14, 2.71 +Min[float32](a, b) +``` + +--- + #### Type Inference ```go @@ -172,6 +184,54 @@ func Min[T constraints.Ordered](x, y T) T { --- +```go +type Liter float64 + +type Meter float64 + +type Kilogram float64 +``` + +```go +func Min[T float64](x, y T) T { + if x < y { + return x + } + return y +} +``` + +```go +var a, b Liter = 1, 2 +Min(a, b) // Errore +``` + +--- + +```go +type Liter float64 + +type Meter float64 + +type Kilogram float64 +``` + +```go +func Min[T ~float64](x, y T) T { + if x < y { + return x + } + return y +} +``` + +```go +var a, b Liter = 1, 2 +Min(a, b) // Ok +``` + +--- + ```go package constraints @@ -204,16 +264,6 @@ type Unsigned interface { --- -```go -type Liter float64 - -type Meter float64 - -type Kilogram float64 -``` - ---- - @@ -396,7 +446,7 @@ func WriteOneByte[T io.Writer](w T, data byte) { ... d := &bytes.Buffer{} -WriteOneByte(d, 42) +WriteOneByte[*bytes.Buffer](d, 42) ``` --- @@ -470,14 +520,14 @@ Utility HTTP --- ```go +// library code type Validator interface { Validate() error } func DecodeAndValidateJSON[T Validator](r *http.Request) (T, error) { var value T - err := json.NewDecoder(r.Body).Decode(&value) - if err != nil { + if err := json.NewDecoder(r.Body).Decode(&value); err != nil { var zero T return zero, err } @@ -494,6 +544,7 @@ func DecodeAndValidateJSON[T Validator](r *http.Request) (T, error) { --- ```go +// client code type FooRequest struct { A int `json:"a"` B string `json:"b"` @@ -509,9 +560,9 @@ func (foo FooRequest) Validate() error { return nil } +``` -... - +```go foo, err := DecodeAndValidateJSON[FooRequest](r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -562,6 +613,50 @@ var foo Validator = FooRequest{} +# Confronto +Vediamo un attimo come fungono internamente le generics del Go + +--- + +```c +// C? +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) +``` + +```cpp +// C++ +template +T min(T const& a, T const& b) +{ + return (a < b) ? a : b; +} +``` + +--- + +```go +// Go +func Min[T constraints.Ordered](x, y T) T { + if x < y { + return x + } + return y +} +``` + +```rust +// Rust +??? +``` + +--- + + + # Pattern (2) Vediamo un analogo di `PhantomData` dal Rust per rendere _type-safe_ l'interfaccia di una libreria @@ -768,4 +863,30 @@ func AwaitAll(ws ...Waiter) error { --- + + +# Conclusione + +--- + + + +### Regole generali + +Per scrivere _codice generico_ in Go + +- Se l'implementazione dell'operazione che vogliamo supportare non dipende del tipo usato allora conviene usare dei **type-parameter** + +- Se invece dipende dal tipo usato allora รจ meglio usare delle **interfacce** + +- Se invece dipende sia dal tipo e deve anche funzionare per tipi che non supportano metodi (ad esempio per i tipi primitivi) allora conviene usare **reflection** + +--- + # Fine :C + +_Domande_