2016-10-05 13 views
3

3進演算子で使用しているif-elseステートメントを置き換えると、コードを実行しようとするとコンパイルエラーが発生することに気付きました。私は犯人がforeach()ループだと信じています。if-elseです。この場合、三項演算子がif-else構造と同じように動作していない理由を知っていますか?三項演算子はiterative演算子を許可しませんが、if-elseは実行しますか?

私のコードは、食料品のリストで、この

#!/program/perl_v5.6.1/bin/perl5.6.1 

use strict; 
use warnings; 


my $fruits_array_ref = &get_fruits(); 
if($fruits_array_ref != 0) { 
    print("$_ is a fruit.\n") foreach(@$fruits_array_ref); 
} 
else { 
    print("Maybe you like vegetables?\n"); 
} 


sub get_fruits() { 
    my @fruit_list; 
    my $shopping_list = "/home/lr625/grocery_items"; 

    open(my $shopping_list_h, "<", $shopping_list) or die("Couldn't open.\n"); 
    while(my $line = <$shopping_list_h>) { 
     next if $line =~ /^\#/; 
     chomp($line); 
     push(@fruit_list, $line); 
    } 
    close($shopping_list_h) or die("Couldn't close.\n"); 

    scalar(@fruit_list) > 0 ? return(\@fruit_list) : return(0); 
} 

私のデータは

# this is a header 
# to my grocery list 
apple 
banana 
grape 
orange 

のように見えるように私は、main関数で次のように見えるように?:オペレータとif-elseを交換しています見えます。

my $fruits_array_ref = &get_fruits(); 
$fruits_array_ref != 0 ? print("$_ is a fruit.\n") foreach(@$fruits_array_ref) : print("Maybe you like vegetables?\n"); 

また、私のエラーは言います。 test.plライン8で

構文エラーは、test.plの近く ")foreachの"

実行は、コンパイルエラーが原因で中止されました。

+0

これは問題とは関係ありませんが、実際にPerl 5.6.1を使用している場合は、5.18や5.22などの新しいバージョンに更新する必要があります。 5.6は本当に、本当に古いです。しかし、あなたのコードを5.22.1で試してみたところ、同じ結果が得られました。 – PerlDuck

+0

私はしたいと思いますが、私は仕事が私に与えるすべてのものについています。私が得たものとやらなければならない。 @chorobaは、三項演算子のオペランドにコントロール構造を適合させようとしていることをうまく説明しているので、doを使って試してみるか、if-elseの予測可能な振る舞いに従います –

+1

あなたはインフェルノが答えていることを吸収する時間を取ることをお勧めします。あなたは "巧妙な"解決策に近づく危険性があるようであり、メンテナンスは賢明ではありません。 – tjd

答えて

8

if-elseはフロー制御構造体であり、?-:はオペランドとして式をとる演算子です。 foreachはフロー制御構造であり、式ではありません。

あなたはdoを使って表現へのコードの任意のブロックをオンにすることができます

$fruits_array_ref != 0 
    ? do { print "$_ is a fruit.\n" for @$fruits_array_ref } 
    : print "Maybe you like vegetables?\n"; 

しかし、なぜ?

1

三項演算子は?:引数を取るin perlopを参照してください。式を評価し、その結果を使用することができます。しかし、ループは式ではなく、内部で実行することはできません。デモンストレーションのために

- あなたが主張した場合は、副作用プリントとして

sub greet { say "hello" for 1..3 } 

my $x = 1; 
($x == 1) ? greet() : say "bye"; 

Actualyは、生産コードでこれをやってする関数を呼び出すことができますが異なる問題であり、おそらく悪い考えです。全体的なポイントは、私たちが通常やりたいこととは反対の副作用に完全に依存することです。


は、上記の私のコメントを説明するために - 三項演算子の主なポイントは、1つのステートメントで、2つの値の間の選択で、 返り値にあります。それはif-elseと "同等"ですが、その使用は(理想的には)非常に異なることを意味します。したがって、何らかの理由で ?:引数の内部で他の処理を行うことは、返される値を生成することを意図しているため、実際には表記法の悪用、副作用です。それを印刷することは、値を生成して返すという考え方とは逆です。これは批判ではなく、演算子は構文上のショートカットとして頻繁に使用されます。

この意味で、表示されていることを行うためにif-elseに戻すことをおすすめします。

1

foreachステートメント修飾子は、ステートメントの最後にのみ使用できます。

なぜあなたは?:を使用していますか?あなたは通常、1つの結果が必要な場合にのみそれを行います。

あなたはdo {...}print...foreach...をラップすることができ、またはあなたがmapの代わりforeachを使用することができます。あるいはif/elseのままにしておきます。

4

他の回答は、あなたが試した方法で三項演算子を使うことができないことをすでに指摘しています。完全を期すために、あなたにいくつかの賢明な利用の例を与えるために、以下の例を見てみましょう:

#1:サブルーチンの引数ここ

testSub($var eq 'test' ? 'foo' : 'bar'); 

として使用され、あなたはどのようにサブルーチン見ることができます$varが文字列testと等しい場合、が引数fooで呼び出されます。そうでなければtestSubbarで呼び出されます。サブ引数としてif-else構造体を使用できないため、これは便利です。

#2:三項演算子はif-else構造に単純な置き換えとして意図されていない

my $result = $var eq 'test' ? 'foo' : 'bar'; # $result will contain 'foo' or 'bar' 

条件割り当てに使用。値(ここではfooまたはbarのいずれか)を返すので、この値を使用することも意味があります。戻り値を使用するつもりがない場合は、通常はif-elseにしてください。