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.

2.7 KiB


Confronto con altri linguaggi

Vediamo come funzionano le generics in Go confrontandole con altri linguaggi


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++

template<typename T>
T min(T const& a, T const& b)
{
    return (a < b) ? a : b;
}

Impl. ⇝ se funziona allora ok


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.

// 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.

// Ok
use std::marker::PhantomData;

struct Foo<T> { a: String, foo_type: PhantomData<T> }

func Resolve[T](value T) *Promise[T] {
    return &Promise{ value: value }
}

func Reject[T](err error) *Promise[T] {
    return &Promise{ error: err }
}

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)
    }
    ...

    ...
    done := make(chan struct{})
    go func() {
        defer close(done)
        wg.Wait()
    }()

    select {
    case err := <-errChan:
        return err
    case <-done:
        return nil
    }
}

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)
    })
}
err := AwaitAll(
    ResolveInto(httpRequest1, &result1), // :: *Promise[int]
    ResolveInto(httpRequest2, &result2), // :: *Promise[struct{ ... }] 
    ResolveInto(httpRequest3, &result3), // :: *Promise[any]
    timer1,                              // :: *Promise[struct{}]
)
...