2011-02-04 10 views
30

mini-esempio:Come avvolgere una funzione usando varargin e varargout?

function varargout = wrapper(varargin) 
varargout = someFunction(varargin); 

Ecco come lo farei prima. Ad esempio, se lo someFunction = ndgrid restituisce un errore non definito per gli array di celle, il tentativo successivo era invece di utilizzare someFunction(varargin{:}). Questa è una chiamata riuscita, ma chiamare [a,b] = wrapper([1,2], [3,4]) non produce lo stesso risultato di una chiamata diretta a ndgrid, quindi cosa sto facendo male?

risposta

35

In realtà, la risposta di Mikhail non è giusta. Nel caso in cui someFunction è una funzione che restituisce un valore anche se non ne viene richiesto nessuno, ovvero come una funzione indica che il valore deve essere assegnato a ans, il wrapper di Mikhail fallirà. Per esempio, se someFunction sono stati sostituiti con il peccato e confrontato in esecuzione involucro contro l'esecuzione direttamente il peccato, che ci si vede:

>> wrapper(0) 
>> sin(0) 

ans = 

    0 

Il modo giusto per fare questo è

function varargout = wrapper(varargin) 
[varargout{1:nargout}] = someFunction(varargin{:}); 

Il motivo per cui funziona è a causa di un caso limite poco conosciuto nelle regole di indicizzazione MATLAB che è esistito precisamente per questo caso da almeno R2006a (probabilmente più lungo). È qualcosa di una verruca nell'indicizzazione di MATLAB ma è stato ritenuto necessario per gestire questo genere di cose.

La regola è:

Quando si esegue l'assegnazione subscripted, se

  • pedice-assegnando ad una variabile non inizializzata, E
  • la variabile non inizializzata è parentesi graffe indicizzato, E
  • la l'indice nelle parentesi graffe è vuoto, E
  • il lato sinistro viene visualizzato all'interno di parentesi quadre, E
  • lato destro risolve in un valore/restituisce un'uscita

Poi la variabile non inizializzata è assegnata una cella scalare che contiene il valore restituito dal lato destro.

Ad esempio:

>> clear uninit % just to make sure uninit is uninitialized 
>> [uninit{[]}] = sin(0) 

uninit = 

    [0] 
+1

+1 e grazie a queste intuizioni profonde! Dove hai preso le regole sopra? – Mikhail

+7

Beh, a dire il vero, aiuta se si ha accesso al codice sorgente ... Io lavoro per The MathWorks. Non sono sicuro se questo è documentato ovunque ufficialmente. È una di quelle cose che aiuta l'utente avanzato ma potrebbe facilmente confondere completamente i principianti. Tuttavia, sono sicuro che questo comportamento non cambierà, perché è necessario per gestire questo caso. – SCFrench

+0

Grazie per la condivisione, questo mi ha infastidito per molto tempo! – Erik

6
function varargout = wrapper(varargin) 

if ~nargout 
    someFunction(varargin{:}); 
else 
    [varargout{1:nargout}] = someFunction(varargin{:}); 
end 
+0

Oh, mi hai battuto sul tempo di 30 secondi :) Ho avuto esattamente la stessa risposta. – Edric

1

Se il numero di argomenti di uscita è lo stesso del numero di argomenti di input, è possibile utilizzare

function varargout = wrapper(varargin) 
[varargout{1:nargin}] = someFunction(varargin{:}); 

Questo funziona bene con ndgrid.

+2

A parte l'errore di battitura (si intende sicuramente varargout {1: nargout}), si noti che questo approccio restituisce sempre output, quindi la guardia extra "~ nargout" di Mikhail. – Edric

+0

@Edric: Penso che l'utilizzo di 'nargin' sia stato fatto apposta a causa dell'assunzione' nargout = nargin'. In tal caso la protezione '~ nargout' non è necessaria –

+1

@Edric ... vedi anche [risposta di SCFrench] (http://stackoverflow.com/questions/4895556/how-to-wrap-a-function-using- varargin-and-varargout/4910926 # 4910926) perché la guardia in realtà non produce il comportamento desiderato –

Problemi correlati