2017-11-17 15 views
1

私は関数を呼び出すPerlプログラムを持っています。この場合はrefです。結果を確認します。具体的には、変数がハッシュリファレンスであることをテストしています。その場合、ref'HASH'を返します。私はそれをテストし、それは働いた。関数が返す値を連結して出力​​できないのはなぜですか?

その後、同じ呼び出しの結果を表示するprintを追加してログに記録することにしましたが、正しく機能しませんでした。ここでは縮小版である:

use strict; 
use warnings; 

my $book_ref = {}; 
$book_ref->{'title'} = 'The Lord of the Rings'; 

if (ref $book_ref eq 'HASH') { 
    print "ref \$book_ref is a " . ref $book_ref . "\n"; 
} 

print "Program is over\n"; 

が驚いたことに、これは出力した:

ref $book_ref is a Program is over 

そしてstrictを使用してもかかわらず、そしてwarningsどちらもエラーや警告がありました。
refへの呼び出しは全く同じです(コピー&ペースト)が、ifの条件の中で正しく動作しますが、改行文字がはっきりとスキップされるため、何も表示されず、実際には中断されているようです。なぜ行動は変わるのですか?

答えて

7

なぜなら、関数refがかっこなしで呼び出され、これによって行が正しく解析されないからです。 refif内部で呼ばれ

  • 、条件が明確にrefは、その引数が何であるかを完全によく知っていることを意味し、括弧で区切られている:$book_ref。あいまいさはありません。
  • 結果を印刷するときに代わりに、括弧の不足がPerlは意図していなかった方法で行を解析することを意味します:

    1. まずそれが$book_ref"\n"を連結します。 '':スカラコンテキストでは、$book_refしたがって、結果は、文字列そして、refがストリング"HASH(0x1cbef70)\n"に呼び出される"HASH(0x1cbef70)\n"
    2. producing as output an empty stringは、HASH(0x1cbef70)ような文字列に評価されます。
    3. この時点で、printは空の文字列、つまり何も表示せずに停止します。改行文字\nは、すでにrefによって消費されているのでスキップされます。したがって、printにも表示されません。そしてエラーはありません。

このすべてがPerl's operator precedenceから下る:テーブルから、 "関数呼び出しが" 実際に "という名前の単項演算子"(refいる単項演算子)である

(...) 

8. left   + - . 
9. left   << >> 
10. nonassoc  named unary operators 
11. nonassoc  < > <= >= lt gt le ge 
12. nonassoc  == != <=> eq ne cmp ~~ 

(...) 

を。したがって、行8の.演算子は、行10の関数呼び出しよりも優先順位が高くなります。そのため、printの結果は期待されたものではありません。一方、関数呼び出しはeq(12行目)よりも優先順位が高いため、ifのすべてが期待通りに機能します。

問題を優先させる解決策は、使用することです。

  • 可能性が関数呼び出しを強調するために括弧を使用することです:

    print "ref \$book_ref is a " . ref($book_ref) . "\n"; 
    
  • もう一つ、私はあまり好きではなく、それにもかかわらず動作しますが、連結されなければならない文字列を分離するために括弧を使用することです、ちょうどref前開きブラケットを置くことによって:

    print "ref \$book_ref is a " . (ref $book_ref) . "\n"; 
    
  • 別の可能なアプローチは、COMMEにzdimによって提案します私が最初に私は、コードを読みやすくするために括弧を避けることにしましたifを書いたとき

    print "ref \$book_ref is a ", ref $book_ref, "\n"; 
    

:NT、コンマを使用することです。それから私はそれをコピーし、問題に気付かなかった。私はバグを見つけるために2時間を無駄にしてしまった。

他の場所(別のprintなど)にコピーすると、問題を防ぐ括弧もコピーされることが保証されるため、最善の解決策が最初のようです。 2番目のものでは、かっこがいかに重要で、それらをコピーしないかが分かりません。そして第3のものは、あなたがいつもカンマを使用しなければならないことを覚えている場合にのみ働きます。だから、彼らは働いていますが、私はそれらを安全性が低いと考えています。

printfを使用することをお勧めします。書式指定子や式の補間が必要です(print "ref \$book_ref is a ${\ ref $book_ref }\n";など)。

ボトムライン:は常にかっこを使用します

+1

また、[print LIST](https://perldoc.perl.org/functions/print.html)による「印刷」値が「、(コード)」、「\ n」であるカンマを使用してください。 – zdim

+1

または、 printf' – toolic

+0

式補間を使う: 'print" ref \ $ book_refは$ {\ ref $ book_ref}です\ n " – mwp

関連する問題