2014-10-01 22 views
8

Un oggetto di qualsiasi tipo può essere assegnato a un'interfaccia vuota. Ad esempio, abbiamo la seguente funzioneInterfaccia vuota Golang {} nella funzione tipo

func Println(i interface{}) { 
    fmt.Println(i) 
} 

Possiamo chiamarla con

Println(3) 
Println(1.5) 
Println("Hello") 

Ma io cann't ottenere la stessa cosa per il tipo di funzione

func Map(fn func(interface{})) { 
    ...... 
} 

non posso chiamare questo con
Map(func(i int) {......})
perché il tipo func (int) è diverso dal tipo func (interfaccia e {}).

Ma quando definisco func (interface {}), intendo davvero qualsiasi tipo di parametri di input. Come posso ottenere questo in Golang

+0

Sono diversi "tipi". Una funzione che accetta un'interfaccia e una funzione che accetta un int sono cose diverse. –

+0

Sì, so che i tipi sono diversi. Ma è possibile per me definire un tipo di funzione per accettare qualsiasi parametro di tipo? –

risposta

11

Fallisce perché le firme non corrispondono.

Quando si chiama Println(3), la funzione non sta prendendo un numero intero come primo argomento. Piuttosto, il numero intero viene impacchettato all'interno di una variabile interface{} (una conversione automatica, poiché gli interi sono conformi all'interfaccia) e tale variabile viene passata alla funzione. Questa conversione avviene dal lato chiamante, quindi il processo di chiamata della funzione è diverso dal chiamare una funzione corrispondente a func(i int).

Se si desidera scrivere una funzione che accetta funzioni unarie arbitrarie, è necessario dichiararlo per prendere una variabile interface{} come argomento e quindi controllare il valore utilizzando il pacchetto reflect. Il pacchetto reflect può anche aiutare a chiamare funzioni arbitrarie in cui non si conosce la firma al momento della compilazione.

Ad esempio:

func Map(f, v interface{}) interface{} { 
    fn := reflect.ValueOf(f) 
    fnType := fn.Type() 
    if fnType.Kind() != reflect.Func || fnType.NumIn() != 1 || fnType.NumOut() != 1 { 
     panic("Expected a unary function returning a single value") 
    } 
    res := fn.Call([]reflect.Value{reflect.ValueOf(v)}) 
    return res[0].Interface() 
} 

Questo chiamerà la funzione data f con l'argomento v e restituire il risultato. Dato che v è assegnabile al primo argomento di f, la chiamata avrà esito positivo senza panico. Puoi provare questo esempio qui: http://play.golang.org/p/kkBu56JYb8

+1

Grazie per l'ottima risposta. In realtà so come usare l'interfaccia {} e riflettere il pacchetto per raggiungere questo obiettivo. Ma chiedere al chiamante di fornire una funzione non intuitiva con l'interfaccia {} non è abbastanza carino. Come possiamo ottenere la conversione automatica da int a interface {}? –

+1

@YiqunHu non puoi. – OneOfOne

+1

Questo è esattamente il motivo per cui la mancanza di generici paralizza gli aspetti funzionali della lingua. – jocull

Problemi correlati