【问题标题】:Why does invoking print in a subroutine append 1 to the string?为什么在子例程中调用 print 会将 1 附加到字符串?
【发布时间】:2010-10-31 07:09:39
【问题描述】:

我创建了以下子程序性别来随机打印字符串 MALE 或 FEMALE。当调用子程序时,打印命令在字符串末尾添加一个“1”后缀。请参阅下面的示例代码和输出:

sub gender { 
    if ( (int rand(100)) >50) {
        print "MALE  ";
    }
    else {
        print "FEMALE";
    }
}   

foreach (1..5) {
    print &gender, "\n"; 
} 

注意“1”是“MALE”或“FEMALE”的后缀

输出:

FEMALE1
FEMALE1
MALE  1
MALE  1
FEMALE1
MALE  1

我正在使用为 MSWin32-x86-multi-thread 构建的 perl v5.8.9 v5.8.9

Binary build 826 [290470] provided by ActiveState @987654321@ Built May 24 2009 09:21:05

【问题讨论】:

    标签: perl printing return-value subroutine


    【解决方案1】:
    print &gender
    

    调用性别函数并打印它返回的内容。性别本身,作为它在任一分支中所做的最后一件事,打印一个字符串。隐式地,它返回其中最后一个表达式的结果(print "MALE" 或 print "FEMALE"),并且 print 成功时返回 1。

    所以要么这样做:

    sub gender { if ( rand(100) >= 50 ) {print "MALE  ";}  else {print "FEMALE";}}
    foreach (1..5) { &gender();  print "\n"; } 
    

    或者这个:

    sub gender { if ( rand(100) >= 50 ) {return "MALE  ";}  else {return "FEMALE";}}
    foreach (1..5) { print &gender(), "\n"; }
    

    另外,请注意&gender,带&但不带括号,是一种特殊形式的函数调用,通常不是人们想要使用的;删除 & 或在您的调用中添加空括号。

    我还更正了 if 测试以返回男性 50% 的时间和女性 50% 的时间,而不是分别返回 49% 和 51%。

    【讨论】:

    • 或者只是去掉括号,因为在调用之前已经声明了 sub。最佳做法通常是无论如何都使用空括号
    • 完全无条件地删除 &。在现代 Perl 代码中,您应该接触 & 的唯一常见情况是引用子例程时。 (它还有其他用途,但它们不为人知。)
    • 忽略原型。耶。 打哈欠
    • 如果你想让它更清楚,即:为了给傻瓜解释它,sub gender { return 1 }; print gender(), "\n"; 当然会打印一个 1。if( 1 == print "hello" ) { print "printing works!" } 证明 print 也返回一个值,没有人会想到print ( ( print "male" ) , "\n" ) 现在是明智的代码吗?
    【解决方案2】:

    让我们用你的代码来习惯用法:

    print gender(), "\n" 
        for 1..5;
    
    sub gender {
        return  int rand(100) > 50 ? 'MALE' : 'FEMALE';
    }
    

    那么,我做了什么?

    第一:

    1. gender sub 不应使用 & 且没有括号来调用。这会在传递给调用者的参数上调用子例程。当您有一堆常见的参数清理代码时,这很方便。但这在这里是不可取或不需要的。
    2. 我将 sub 放在其他代码之后,因为我喜欢从高级到具体阅读我的代码——这与 C 强制您组织事物的方式相反。我不喜欢从下往上阅读我的代码,所以我这样做了。这纯粹是个人喜好。做任何让你开心的事。或者,如果您必须与他人合作,请遵循您同意的标准。
    3. 我将foreach 缩短为for。它们做的事情完全相同,只需要更少的字符。
    4. 我使用for 作为语句修饰符。换句话说,我做了一个简单的声明print $_, "\n"; 并将for 添加到末尾。对于简单的任务,它比使用块更好。再说一次,这是我的看法。有些人谴责语句修饰符为 evil 并且不受欢迎。如果您决定使用它们,请保持简单。 YMMV。
    5. 我去掉了ysth提到的多余的打印。
    6. 我没有使用大的 if/else 块,而是使用三元运算符(好吧,它实际上只是 a 三元运算符,但人们称它为 the 三元运算符) .它计算一个测试值,并根据测试的布尔值返回两个表达式之一的结果。当您需要在分配中使用 if/else 逻辑时,它会很方便。

    【讨论】:

    • int 并没有真正做任何实际的事情。它确实迫使概率发生小幅变化——int(50.9) 是 50,因此是收益率FEMALE。没有int,50.9 产生MALE。我想这是一个意想不到的功能,但我不想改变概率。也许这就是数字 7 的用途。
    • 没错,int() 只是从我试图解决的工作中继承而来。它在讨论的问题中没有真正的目的。
    【解决方案3】:

    如果没有明确的return,Perl 子程序将返回最后评估的值。 gender 返回一个 1,因为在两个执行路径中,它都调用了返回一个 1 的 print

    您应该让gender 返回一个字符串,然后调用者prints 将其返回,或者让gender 进行打印,并且让调用者不对返回值做任何事情。

    【讨论】:

      【解决方案4】:

      感谢大家帮助我解决这个问题。我找到了一种制作我想要的图表的方法。 这是我最终做到的方式;

      print   "GENDER    NAME   AGE   HEIGHT  WEIGHT \n";
      foreach (1..10) {                       ## Starting foreach loop
      $age    = int(rand( 50))+10;
      $height = int (rand(40)) + 50;
      $weight = int (rand (100)) + 100;
      sub randchar4bit {(chr int rand(25)+65).(chr int rand(25)+65). (chr int rand(25)+65).(chr int rand(25)+65)};
      sub gender { return (int rand(100)>50)? "MALE    " : "FEMALE  ";} ;
      
      print gender(), "  ", &randchar4bit,   "    $age     $height      $weight   style 1\n";
      }; ## closing foreach loop 
      

      它会产生一个不错的输出:

      GENDER    NAME   AGE   HEIGHT  WEIGHT
      FEMALE    HHRN    41     67      165   style 1
      MALE      HNMF    27     63      187   style 1
      MALE      NLDB    26     54      165   style 1
      FEMALE    REMB    33     71      118   style 1
      MALE      TWEW    10     57      122   style 1
      MALE      OCSC    35     80      168   style 1
      FEMALE    TKTR    25     64      179   style 1
      MALE      GMYN    47     73      123   style 1
      MALE      YKUG    50     79      148   style 1
      FEMALE    HDFW    47     73      159   style 1
      

      【讨论】:

        猜你喜欢
        • 2012-09-29
        • 2017-12-10
        • 1970-01-01
        • 2014-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多