开发者

Why does invoking print in a subroutine append 1 to the string?

I have created the following subroutine gender to randomly print string MALE or FEMALE. When subroutine is invoked, the print command suffixes a "1" at the end of the string. See the sa开发者_如何学Cmple code and output below:

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

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

Notice a "1" is suffixed to "MALE" OR "FEMALE"

OUTPUT:

FEMALE1
FEMALE1
MALE  1
MALE  1
FEMALE1
MALE  1

I am using perl v5.8.9 v5.8.9 built for MSWin32-x86-multi-thread

Binary build 826 [290470] provided by ActiveState http://www.ActiveState.com Built May 24 2009 09:21:05


print &gender

calls the gender function and prints what it returns. gender itself, as the last thing it does in either branch, prints a string. Implicitly, it returns the result of the last expression in it (the print "MALE" or print "FEMALE"), and print, when it succeeds, returns 1.

So either do this:

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

or this:

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

Also, note that &gender, with & but without parentheses, is a special form of function invocation that isn't usually what people mean to use; either drop the & or add empty parentheses to your call.

I've also corrected the if test to return male 50% of the time and female 50% of the time, instead of 49% and 51% respectively.


Let's get idiomatic with your code:

print gender(), "\n" 
    for 1..5;

sub gender {
    return  int rand(100) > 50 ? 'MALE' : 'FEMALE';
}

So, what did I do?

First:

  1. The gender sub should not be called with the & and no parens. This invokes the subroutine on the arguments passed to its caller. This is handy when you have a bunch of common argument sanitizing code. But it is not desirable or needed here.
  2. I put the sub after the other code because I like to read my code from high level to specific--the opposite of how C forces you to organize things. I don't like reading my code from the bottom up, so I did it this way. This is purely a personal preference. Do whatever makes you happy. Or if you have to work with others, follow the standard you've agreed upon.
  3. I shortened foreach to for. They do exactly the same thing, one takes fewer characters.
  4. I used for as a statement modifier. In other words I took a simple statement print $_, "\n"; and tacked the for onto the end. For simple tasks it is nicer than using a block. Again, this is my opinion. Some people decry statement modifiers as evil and unwelcome. If you decide to use them, keep it simple. YMMV.
  5. I got rid of the extra unneeded print ysth mentioned.
  6. Instead of using a big if/else block, I used the ternary operator (OK, it's really just a ternary operator, but people call it the ternary operator). It computes a test value and depending on the boolean value of the test, returns the result one of two expressions. It is handy when you want if/else logic in an assignment.


Without an explicit return, the Perl sub will return the last evaluated value. gender returns a 1 because in both execution paths, it calls print which returns a 1.

You should either be having gender return a string, which the caller then prints, or have gender do the printing, and have the caller not do anything with the return value.


Thank You everyone for helping me out with this. I found a way to make a chart I wanted. Here is how I finally did it;

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 

It generates a nice output:

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜