2012-01-19 3 views
22

Sono in Perl 5.8 e ho bisogno di assegnare un valore predefinito. Ho finito per fare questo:Assegnare usando l'operatore ternario?

if ($model->test) { 
    $review = "1" 
} else { 
    $review = '' 
} 

Il valore della $model->test sta per essere o "1" o non definito. Se c'è qualcosa in $model->test, impostare $review su "1" altrimenti impostarlo su ''.

Perché non è Perl 5.10 Non riesco a utilizzare il nuovo operatore definito-o swanky. La mia prima reazione è stata quella di usare l'operatore ternario come questo ...

defined($model->test) ? $review = "1" : $review = ''; 

ma che non ha funzionato neanche.

Qualcuno ha un'idea su come assegnarlo in modo più efficiente? Janie

+0

Si dovrebbe davvero impostarlo a '1' non' '' '. Entrambi hanno la stessa rappresentazione di stringa (''''). L'unica differenza è che '''' avviserà se si tenta di usarlo come un numero, dove come '! 1' non lo farà. (Supponendo che tu abbia sempre "usato avvertenze;" all'inizio di ogni parte del codice Perl come dovresti.) –

risposta

32

mi piacerebbe di solito scrivere questo come:

$review = (defined($model->test) ? 1 : ''); 

dove le parentesi sono per la chiarezza per le altre persone che leggono il codice.

+0

Grazie Greg! Mi sento strano anche solo a chiedere perché sembra che sarebbe così semplice. (ed è!) JW –

+0

@JaneWilkie In realtà, è più facile di così, anche. Vedi la mia risposta. – tchrist

+0

Ovviamente la soluzione migliore sarebbe cambiare la definizione di MySQL in CHAR (1) anziché BIT (1), ma purtroppo la politica di cambiare qualcosa di così semplice nel nostro ambiente di produzione è enorme. –

9

$model->test sta per essere o "1" o non definito. Se c'è qualcosa in $model->test, impostare $review a "1" altrimenti impostarla ''

Poi basta usare questo:

$review = $model->test || ""; 
+0

Tom e Foy nella stessa discussione. Dov'è Larry Wall? Voglio che tutti noi siamo schierati in modo che io possa avere la mia foto scattata con voi ragazzi. – Alhadis

2

Prima di tutto, "che non ha funzionato neanche" Non è la cosa più utile potresti dircelo. È importante sapere esattamente in che modo non ha funzionato: cosa ha fatto, cosa ti aspetti e come differiscono?

Ma il problema con

defined($model->test) ? $review="1" : $review=''; 

è precedenza degli operatori. L'operatore condizionale ? : lega più saldamente di quanto l'operatore di assegnazione =, in modo che il sopra è equivalente a:

(defined($model->test) ? $review="1" : $review) = ''; 

Quindi, se $model->test è definito, lo fa l'equivalente di

$review = "1" = ''; 

È possibile risolvere questo problema con parentesi:

defined($model->test) ? ($review="1") : ($review=''); 

Ma davvero, perché vorresti? L'operatore condizionale (ternario) è utile quando si desidera utilizzare il risultato.Se il risultato sta per essere scartato, in quanto è qui, è più chiaro (e, come avete visto, meno soggetto a errori) per utilizzare un if/else:

if (defined($model->test) { 
    $review = "1"; 
} 
else { 
    $review = ""; 
} 

o, se insistete sulla scrittura su una sola riga:

if (defined($model->test) { $review = "1"; } else { $review = ""; } 

Se davvero si vuole usare un'espressione condizionale, si può fare questo:

$review = defined($model->test) ? "1" : ""; 

che è probabilmente un modo ragionevole per farlo.

BUT:

L'operatore defined stessa cede o "1" (true) o "" (false). quindi il tutto può essere ridotto a:

$review = defined($model->test); 
+0

Cosa succede se 'undef' è solo un valore falso, e il metodo viene riscritto per restituire' '' 'o' 0' come valore falso? –

+0

@BradGilbert: Quindi suppongo che non vorreste applicare 'defined' ad esso. Ovviamente devi sapere che cosa restituisce il metodo per poterlo utilizzare. –

+0

Non è compito di test() fornire valori adatti per ogni altro uso e sarebbe una cattiva forma affidarsi a questo. Quel genere di cose porta a un accoppiamento stretto ea test severi. –

20

Hai un problema di precedenza. Quello che hai è lo stesso di

(defined($model->test) ? $review="1" : $review) = ''; 

Si potrebbe farlo funzionare con parents.

my $review; $model->test ? ($review='1') : ($review=''); 

Ma è molto più pulito spostare l'incarico.

my $review = $model->test ? '1' : ''; 

Naturalmente, si può semplicemente utilizzare

my $review = $model->test || ''; 

Ma perché cambiare undef ad una stringa vuota?

my $review = $model->test; 
1
my $result = defined $model->test ? '1' : ''; 
+0

Questo imposta '$ result' su quasi lo stesso valore di' $ result = defined $ model-> test; '. La differenza principale è che il tuo avverte se usato come un numero. –

2

Suppongo che $model->test si suppone per restituire un valore vero o falso.

A meno che non si afferma espressamente che il valore falso è undef, il metodo potrebbe essere riscritto per iniziare a restituire qualche altro valore falso, invece. Quale potrebbe interrompere tutto ciò che controlla solo se il valore è definito.
(penso che sia un bug che il metodo restituisce undef invece del valore falso canonica.)

Quindi il modo migliore per impostare $review è quello di testare la veridicità del valore restituito; non è definizione.

my $review = $model->test ? 1 : ''; 

vorrei sottolineare che questo ha ancora un bug in esso. Se si desidera poter utilizzare il valore come numero, emetterà avvisi se era falso.

Per risolvere il problema è necessario restituire !1 (valore falso canonico), che restituirà un valore che è la stringa '', ma ha anche il valore numerico di 0.

my $review = $model->test ? 1 : !1; 

Si noti che quest'ultimo possa essere semplificato a poco:

my $review = !! $model->test; # invert it twice 

Se si vuole solo modificare il valore solo quando è falsa, è possibile utilizzare l'operatore OR ||.

my $review = $model->test || !1; 

Se davvero solo vuole sapere se è definito, o no perché non basta usare defined.

my $review = defined $model->test; 

Se si desidera cambiare il valore solo quando non è definito, e si dispone di Perl 5.10 o più recente è possibile utilizzare il defined-or operator (//).

my $review = $model->test // !1; 

Su un vecchio Perl, che richiederebbe più di una statement.

my $review = $model->test; 
$review = !1 unless defined $review; 
7

Oltre l'operatore condizionale, spesso mi piace usare do, che restituisce il valore dell'ultima espressione valutata:

my $review = do { 
    if(...) { 'foo' } 
    elsif(...) { 'bar' } 
    elsif(...) { 'baz' } 
    else   { 'defaut' } 
    }; 
+0

Questo è un po 'eccessivo in questo caso. Vale sempre la pena aggiungere un'altra tecnica alla tua cassetta degli attrezzi, grazie. –