詭異的Perl ?: 運算子陷阱

來源:互聯網
上載者:User

前幾天寫一個perl的指令碼 在:?運算子上遇到了一個很詭異的問題

$data->{$id}->{'total'} ?
    $data->{$id}->{'ratio'} = sprintf("%.2f%%", 100 * $data->{$id}->{'succ'} / $data->{$id}->{'total'}) : 
    $data->{$id}->{'ratio'} = 'N/A';

我的本意是 如果 $data->{$id}->{'total'} 未定義則不計算ratio,把ratio賦值為N/A. 這條語句等同於

if ( $data->{$id}->{'total'} ) {
    $data->{$id}->{'ratio'} = sprintf("%.2f%%", 100 * $data->{$id}->{'succ'} / $data->{$id}->{'total'});
} else {
    $data->{$id}->{'ratio'} = 'N/A';

可奇怪的是,當無論total是否有定義 ratio的結果居然都是N/A. 可後面if……else……的語句是沒有問題的,真的是讓我百思不得其解.
跑去查Perl的文檔, 其中對於?:的運算子號的解釋是
Ternary ``?:'' is the conditional operator, just as in C. It works much like an if-then-else. If the argument before the ? is true, the argument before the : is returned, otherwise the argument after the : is returned.

貌似是return the argument, 於是乎 突然有了一個想法, 在前後都加上了括弧……

$data->{$id}->{'total'} ?
    ( $data->{$id}->{'ratio'} = sprintf("%.2f%%", 100 * $data->{$id}->{'succ'} / $data->{$id}->{'total'}) ) : 
    ( $data->{$id}->{'ratio'} = 'N/A' );

……居然就對了. 既然是return the argument, 我就又換了一種方式:

$data->{$id}->{'ratio'} = $data->{$id}->{'total'} ?
    sprintf("%.2f%%", 100 * $data->{$id}->{'succ'} / $data->{$id}->{'total'}) : 
    'N/A';

雖然後面兩種方式都可以理解, 那確實是一種正確的做法. 但為什麼第一種方式的結果不對呢? 難道return the argument的意思就是不要在那裡做賦值運算嗎? 

為了測試, 我又寫了一個簡單的小程式

 1 #!/usr/bin/perl
 2 
 3 use strict;
 4 
 5 my $total = 1;
 6 my $rval;
 7 
 8 $total ? 
 9     $rval = $total :
10     $rval = 'N/A';
11 
12 print $rval, "/n";
13 
14 if ($total) {
15     $rval = $total;
16 } else {
17     $rval = 'N/A';
18 }
19 
20 print $rval;

啟動並執行結果顯示, 無論第5行給$total賦什麼值……包括1, "abc", "true", undef 等,執行的結果第一個print列印出來的都是N/A. 難道 $total? 不等價於 if ($total) 嗎?

很偶然的情況下,發現了一個方法來驗證perl在內部是怎麼解析這些語句的方法:
perl -MO=Deparse,-p -e '$a ? $b=1 : $b=2;'

輸出的結果很是出乎我的意料:
(($a ? ($b = 1) : $b) = 2);

現在情況很明顯了,原來是運算子優先順序的問題!Perl語言中,三元操作符:?優先順序比賦值=要高,C語言裡面=的優先順序比?:高,就不會出現這樣的問題。這幾乎是一個超出常識和習慣和特性,也是一個很容易陷入的陷阱。

解決的辦法也很簡單,寫成 $a ? ($b=1) : ($b=2); 就好了。

這也進一步印證了那條編程法則: 在複雜的操作符運算的時候,用括弧來標識出各個運算的優先順序,即使你認為你瞭解運算的順序。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.