You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
2.7 KiB
Markdown
186 lines
2.7 KiB
Markdown
|
|
---
|
|
|
|
<!-- _class: chapter -->
|
|
|
|
# Confronto con altri linguaggi
|
|
Vediamo come funzionano le generics in Go confrontandole con altri linguaggi
|
|
|
|
---
|
|
|
|
## C
|
|
|
|
```c
|
|
// versione semplificata da linux/minmax.h
|
|
#define min(x, y) ({ \ // block expr (GCC extension)
|
|
typeof(x) _min1 = (x); \ // eval x once
|
|
typeof(y) _min2 = (y); \ // eval y once
|
|
(void) (&_min1 == &_min2); \ // check same type
|
|
_min1 < _min2 ? _min1 : _min2; \ // do comparison
|
|
})
|
|
```
|
|
|
|
Impl. ⇝ _Sostituzione testuale post-tokenizzazione_
|
|
|
|
---
|
|
|
|
## C++
|
|
|
|
```cpp
|
|
template<typename T>
|
|
T min(T const& a, T const& b)
|
|
{
|
|
return (a < b) ? a : b;
|
|
}
|
|
```
|
|
|
|
Impl. ⇝ _se funziona allora ok_
|
|
|
|
---
|
|
|
|
## Rust
|
|
|
|
```rust
|
|
pub fn min<T: PartialOrd>(a: T, b: T) -> T {
|
|
if a < b {
|
|
a
|
|
} else {
|
|
b
|
|
}
|
|
}
|
|
```
|
|
|
|
Impl. ⇝ _Monomorfizzazione_
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
In Rust è obbligatorio utilizzare tutte le generics usate.
|
|
|
|
```rust
|
|
// Ok
|
|
struct Foo<T> { a: String, value: T }
|
|
|
|
// Errore
|
|
struct Foo<T> { a: String }
|
|
```
|
|
|
|
In certi casi però vogliamo introdurle solo per rendere _type-safe_ un'interfaccia o per lavorare con le _lifetime_.
|
|
|
|
```go
|
|
// Ok
|
|
use std::marker::PhantomData;
|
|
|
|
struct Foo<T> { a: String, foo_type: PhantomData<T> }
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
```go
|
|
func Resolve[T](value T) *Promise[T] {
|
|
return &Promise{ value: value }
|
|
}
|
|
|
|
func Reject[T](err error) *Promise[T] {
|
|
return &Promise{ error: err }
|
|
}
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
```go
|
|
type Waiter interface { Wait() error }
|
|
|
|
func (p Promise[T]) Wait() error {
|
|
<-p.done
|
|
return p.err
|
|
}
|
|
|
|
func AwaitAll(ws ...Waiter) error {
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(ws))
|
|
|
|
errChan := make(chan error, len(ws))
|
|
for _, w := range ws {
|
|
go func(w Waiter) {
|
|
defer wg.Done()
|
|
err := w.Wait()
|
|
if err != nil {
|
|
errChan <- err
|
|
}
|
|
}(w)
|
|
}
|
|
...
|
|
```
|
|
|
|
---
|
|
|
|
```go
|
|
...
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
wg.Wait()
|
|
}()
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
return err
|
|
case <-done:
|
|
return nil
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
```go
|
|
func ResolveInto[T any](p *Promise[T], target *T) *Promise[T] {
|
|
return Run[T](func(resolve func(T), reject func(error)) {
|
|
value, err := p.Await()
|
|
if err != nil {
|
|
reject(err)
|
|
return
|
|
}
|
|
|
|
*target = value
|
|
resolve(value)
|
|
})
|
|
}
|
|
```
|
|
|
|
```go
|
|
err := AwaitAll(
|
|
ResolveInto(httpRequest1, &result1), // :: *Promise[int]
|
|
ResolveInto(httpRequest2, &result2), // :: *Promise[struct{ ... }]
|
|
ResolveInto(httpRequest3, &result3), // :: *Promise[any]
|
|
timer1, // :: *Promise[struct{}]
|
|
)
|
|
...
|
|
``` |