2011-01-10 17 views

risposta

5

ho finito con la seguente implementazione:

(defn protocol? [maybe-p] 
    (boolean (:on-interface maybe-p))) 

(defn all-protocols [] 
    (filter #(protocol? @(val %)) (ns-publics *ns*))) 

(defn implemented-protocols [sym] 
    (filter #(satisfies? @(val %) sym) (all-protocols))) 

In primo luogo sembra per tutti i simboli nello spazio dei nomi corrente (si può ovviamente estenderà a tutti i namespace) se sono definizioni di protocolli o net (tutti Protocols). Successivamente cerca un dato simbolo se soddisfa uno di questi protocolli.

Il protocollo? la funzione utilizza la: chiave on-interface che non è documentata, quindi questa funzione non è portabile.

+0

'protocollo?' Fallisce su una mappa ordinata, almeno in Clojure 1.8. Vedi [questa domanda] (http://stackoverflow.com/q/37410580/1393162). –

0

Al momento non riesco a provare questo, ma si potrebbe voler provare il metodo di classe Java: getGenericInterfaces. Questo dovrebbe darti un elenco di interfacce. Ci sono probabilmente altri modi per ottenere queste informazioni usando metodi simili ma non ho guardato.

Se si guarda anche il codice sorgente, vedremo come vengono configurati i protocolli (è possibile ottenere il codice sorgente facendo clic sui collegamenti nell'api del clojure). In Clojure 1.3 v'è una funzione di 'privato' che assomiglia a questo:

(defn- protocol? 
    [maybe-p] 
    (boolean (:on-interface maybe-p))) 

Questa funzione viene utilizzata dalla funzione di Clojure extend per verificare che hai effettivamente fornito un protocollo. Se si esegue la propria funzione in questo modo è possibile filtrare i risultati di getGenericInterfaces. Poiché questo è un dettaglio interno potrebbe essere soggetto a modifiche.

+0

getGenericInterfaces restituisce (clojure.lang.IObj clojure.lang.ILookup clojure.lang.IKeywordLookup clojure.lang.IPersistentMap java.util.Map java.io.Serializable) ma non il protocollo implementato. Credo che dovrò approfondire il codice sorgente per vedere come è fatto. –

+0

Sono appena tornato alla mia macchina, e non ho intenzione di andare oltre. Probabilmente è più semplice usare 'getInterfaces' come alternativa ragionevole a' getGenericInterfaces'. Mi chiedo cosa succederà se tu compili la cosa. – hutch

+2

Parte del punto dei protocolli è che una classe non ha bisogno di implementare un'interfaccia per estendere un protocollo: è possibile definire il proprio protocollo e quindi dire che alcune classi preesistenti lo estendono con '(estendi ExistingClass MyProtocol ...)'. Quindi è naturale avere un modo per chiedere "quali classi estendono questo protocollo" ma non un modo per porre la domanda inversa. –

Problemi correlati