Return 来自嵌套子例程 Perl 的值
Return value from nested Subroutine Perl
我们收到了学校的作业,我们应该在其中制作我们自己的小型简单 Perl 应用程序。我想我会做一个 ATM 模拟器。到目前为止,一切进展顺利;我使用子程序创建了一个菜单(取款、余额、转账)。到目前为止,这是我的代码:
#! /usr/bin/perl
#Written by: Tobias Svenblad, h15tobsv@du.se, Digitalbrott & e-Säkerhetsprogrammet (2015)
#PerlLab03-2c.plx
use warnings;
use strict;
use Term::ANSIColor;
use Text::Format;
my $firstname;
my $lastname;
my $acc_balance = 2451.26;
my $acc_withdraw;
my $clr_scr = join( "", ( "3[2J", "3[0;0H" ) ); #This variable will clear the screen and jump to postion 0, 0.
my $atm = Text::Format->new;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
#Create account message.
my $crt_acc_msg = <<"END_MSG";
\nDear Sir or Madam,\n
We're very happy you've chose us as your bank.
Before we proceed, we need to set-up your account.\n
END_MSG
print $crt_acc_msg;
&acc_create;
&acc_choose;
sub acc_create {
ACC_BEGINNING:
#First name:
print "\nYour first name: ";
$firstname = <STDIN>;
chomp $firstname;
#Last name:
print "\nYour last name: ";
$lastname = <STDIN>;
chomp $lastname;
if ( defined($firstname) && $firstname ne "" ) {
if ( defined($lastname) && $lastname ne "" ) {
goto ACC_PASS;
}
}
else {
print "You didn't fill in first or last name. Try again. \n";
goto ACC_BEGINNING;
}
ACC_PASS:
print "Please wait while the system loads.\n\n";
#sleep(2);
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nWelcome ", $firstname, " ", $lastname, "!\n\n";
}
sub acc_choose {
sub acc_balance {
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nYour balance is: ";
print color('green');
print $acc_balance;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
sub acc_withdraw {
ENTER_AMOUNT:
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nEnter how much you'd like to withdraw: \n";
my $acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.";
goto ENTER_AMOUNT;
}
$acc_balance -= $acc_balance_withdraw;
print "\nYour current balance is now: ";
print color('green');
print $acc_balance;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
sub acc_transfer {
ENTER_AMOUNT:
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nEnter how much you'd like to transfer: \n";
my $acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.";
goto ENTER_AMOUNT;
}
print "\nYour current balance is now: ";
print color('green');
print $acc_balance - $acc_balance_withdraw;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
ACC_CHOOSE:
print "[ ";
print color('cyan');
print "1";
print color('reset');
print " ]";
print "Account Balance\n";
print "[ ";
print color('cyan');
print "2";
print color('reset');
print " ]";
print "Withdraw\n";
print "[ ";
print color('cyan');
print "3";
print color('reset');
print " ]";
print "Transfer\n";
my $choice1 = <STDIN>;
chomp $choice1;
if ( $choice1 == 1 ) {
&acc_balance;
}
elsif ( $choice1 == 2 ) {
&acc_withdraw;
}
elsif ( $choice1 == 3 ) {
&acc_transfer;
}
else {
print "You entered an invalid option. Try again. \n";
goto ACC_CHOOSE;
}
return ();
}
我遇到的问题是当我尝试将 return 的 $acc_balance
值传递给其他子例程时。我试图在嵌套子例程下实现 return($acc_balance );
,但这只会提示我结束应用程序。所以基本上,我想做的是每次提款或转账时更新 $acc_balance
(它们目前在这段代码中是同一件事),但每当我尝试这样做时,它要么不'更新值,否则它只会显示经典的 "Press any key to continue..."
消息。
非常感谢任何帮助!谢谢!
看起来很可爱,但有些事情是不应该做的。我将尝试向您展示 选择 部分。
不要使用 &
调用子程序,而是使用括号,即 acc_choose();
而不是 &acc_choose;
。
不要在 perl 中嵌套 functions/subs。如果你真的想封装东西(我很欣赏并推荐),
使用模块。但这超出了这个问题的范围。稍后你会了解到。
如果不是绝对必要,请不要使用 goto
。它使控制流程变得怪异、难以遵循,并且经常导致意外。
如果你想重复某事 直到满足某个条件——或者换句话说——while某个条件没遇见,
使用 while
循环。
鉴于此,我建议 choose 部分(省略花哨的印刷):
sub acc_balance {
print "\nYour balance is: $acc_balance SEK\n\n";
}
sub acc_withdraw {
my $acc_balance_withdraw = 0;
do {
print "\nEnter how much you'd like to withdraw: \n";
$acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.\n";
}
} while( $acc_balance_withdraw > $acc_balance );
# if you get here, then $acc_balance_withdraw <= $acc_balance, so:
$acc_balance -= $acc_balance_withdraw;
print "\nYour current balance is now: $acc_balance SEK\n\n";
}
# actually almost the same as acc_withdraw() only with
# other screen output and no `-=` operation
sub acc_transfer {
# left as an excercise
}
sub acc_choose {
print "[1] Account Balance\n";
print "[2] Withdraw\n";
print "[3] Transfer\n";
print "[4] Exit\n";
do {
my $choice1 = <STDIN>;
chomp $choice1;
if ( $choice1 == 1 ) {
acc_balance();
}
elsif ( $choice1 == 2 ) {
acc_withdraw();
}
elsif ( $choice1 == 3 ) {
acc_transfer();
}
elsif ( $choice1 == 4 ) {
print "Thank you. Good bye.\n"
}
else {
print "You entered an invalid option. Try again. \n";
}
} while( $choice != 1 && $choice != 2 && $choice != 3 && $choice != 4 );
}
您尝试的一个问题可能是您递归地调用了 acc_choose()
,即您是从其内部调用它。再加上goto
确实可以起到很好的娱乐效果。
祝你好运,继续加油。
哦,然后回答你的问题:现在拥有子例程 return 东西真的很简单。这不是必需的,因为你使用 $acc_balance
的全局变量(也不要这样做),但如果你愿意,你可以让 subs return 像这样的新余额:
sub acc_withdraw {
my $old_balance = shift; # that's the first argument given to this sub
my $acc_balance_withdraw = 0;
do {
print "\nEnter how much you'd like to withdraw: \n";
$acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $old_balance ) {
print "Insufficient funds.\n";
}
} while( $acc_balance_withdraw > $old_balance );
# if you get here, then $acc_balance_withdraw <= $acc_balance, so:
my $new_balance = $old_balance - $acc_balance_withdraw;
print "\nYour current balance is now: $new_balance SEK\n\n";
return $new_balance;
}
# and then...
$acc_balance = acc_withdraw($acc_balance);
我删除了格式和颜色,因为它与问题无关。方法如下:子例程需要的所有内容都来自其参数,它更改的所有内容都将返回。
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
sub create {
print << 'END_MSG';
Dear Sir or Madam,
We're very happy you've chose us as your bank.
Before we proceed, we need to set-up your account.
END_MSG
my ($firstname, $lastname);
my $first = 1;
while (! defined $firstname || ! defined $lastname
|| q() eq $firstname || q() eq $lastname
) {
say "You didn't fill in first or last name. Try again." unless $first;
undef $first;
print "\nYour first name: ";
chomp( $firstname = <STDIN> );
print "\nYour last name: ";
chomp( $lastname = <STDIN> );
}
say "Please wait while the system loads.\n";
say "\nWelcome ", $firstname, " ", $lastname, "!\n";
return ($firstname, $lastname)
}
sub choose {
my $balance = 2451.26;
my @menu = ( 'Account Balance',
'Withdraw',
'Transfer',
'Quit',
);
my $choice = q();
until ('4' eq $choice) {
for my $i (0 .. $#menu) {
say '[ ', $i + 1, ' ] ', $menu[$i];
}
chomp( $choice = <STDIN> );
my @actions = (\&balance,
\&withdraw,
\&transfer,
sub {}
);
my $action = $actions[$choice - 1];
if ($action) {
my $value = $action->($balance);
$balance = $value if defined $value;
} else {
say 'You entered an invalid option. Try again.';
}
}
}
sub balance {
my $balance = shift;
say "\nYour balance is: $balance SEK\n\n";
return $balance
}
sub withdraw {
my $balance = remove('withdraw', @_);
return $balance
}
sub transfer {
my $balance = remove('transfer', @_);
return $balance
}
sub remove {
my ($action, $balance) = @_;
say "\nEnter how much you'd like to $action:\n";
my $remove = <STDIN>;
if ( $remove > $balance ) {
print "Insufficient funds.";
} else {
$balance -= $remove;
}
balance($balance);
}
my ($firstname, $lastname) = create();
choose();
say "Good bye, $firstname $lastname!";
嵌套子程序的嵌套方式与 Pascal 不同。事实上,您不能在 Perl 中嵌套命名子例程。
如图所示,只有在需要引用子例程时才使用&
。
不要使用 goto
。循环更容易理解和管理。
此外,请确保不要在打印重要消息后立即擦除屏幕 ("Insufficient funds")。
我认为您不应该为这项作业使用子例程。但令我担心的是,有人告诉您在调用子例程时要使用 & 符号 &
,并解释了如何使用标签和 goto
。这不适合现代计算机语言,您可以做得更好
例如,我会这样写你的子程序acc_create
sub acc_create {
while () {
print "\nYour first name: ";
chomp (my $firstname = <STDIN>);
print "\nYour last name: ";
chomp (my $lastname = <STDIN>);
last if $firstname and $lastname;
print "You didn't fill in first or last name. Try again.\n";
}
print "Please wait while the system loads.\n\n";
print
$clr_scr,
color('green'), $atm->center("ATM v. 1.20"), color('reset');
print "\nWelcome $firstname $lastname!\n\n";
}
我还有很多话要说,但 Stack Overflow 不是教程的地方
我们收到了学校的作业,我们应该在其中制作我们自己的小型简单 Perl 应用程序。我想我会做一个 ATM 模拟器。到目前为止,一切进展顺利;我使用子程序创建了一个菜单(取款、余额、转账)。到目前为止,这是我的代码:
#! /usr/bin/perl
#Written by: Tobias Svenblad, h15tobsv@du.se, Digitalbrott & e-Säkerhetsprogrammet (2015)
#PerlLab03-2c.plx
use warnings;
use strict;
use Term::ANSIColor;
use Text::Format;
my $firstname;
my $lastname;
my $acc_balance = 2451.26;
my $acc_withdraw;
my $clr_scr = join( "", ( "3[2J", "3[0;0H" ) ); #This variable will clear the screen and jump to postion 0, 0.
my $atm = Text::Format->new;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
#Create account message.
my $crt_acc_msg = <<"END_MSG";
\nDear Sir or Madam,\n
We're very happy you've chose us as your bank.
Before we proceed, we need to set-up your account.\n
END_MSG
print $crt_acc_msg;
&acc_create;
&acc_choose;
sub acc_create {
ACC_BEGINNING:
#First name:
print "\nYour first name: ";
$firstname = <STDIN>;
chomp $firstname;
#Last name:
print "\nYour last name: ";
$lastname = <STDIN>;
chomp $lastname;
if ( defined($firstname) && $firstname ne "" ) {
if ( defined($lastname) && $lastname ne "" ) {
goto ACC_PASS;
}
}
else {
print "You didn't fill in first or last name. Try again. \n";
goto ACC_BEGINNING;
}
ACC_PASS:
print "Please wait while the system loads.\n\n";
#sleep(2);
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nWelcome ", $firstname, " ", $lastname, "!\n\n";
}
sub acc_choose {
sub acc_balance {
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nYour balance is: ";
print color('green');
print $acc_balance;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
sub acc_withdraw {
ENTER_AMOUNT:
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nEnter how much you'd like to withdraw: \n";
my $acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.";
goto ENTER_AMOUNT;
}
$acc_balance -= $acc_balance_withdraw;
print "\nYour current balance is now: ";
print color('green');
print $acc_balance;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
sub acc_transfer {
ENTER_AMOUNT:
print $clr_scr;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');
print "\nEnter how much you'd like to transfer: \n";
my $acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.";
goto ENTER_AMOUNT;
}
print "\nYour current balance is now: ";
print color('green');
print $acc_balance - $acc_balance_withdraw;
print color('reset');
print " SEK\n\n";
&acc_choose;
}
ACC_CHOOSE:
print "[ ";
print color('cyan');
print "1";
print color('reset');
print " ]";
print "Account Balance\n";
print "[ ";
print color('cyan');
print "2";
print color('reset');
print " ]";
print "Withdraw\n";
print "[ ";
print color('cyan');
print "3";
print color('reset');
print " ]";
print "Transfer\n";
my $choice1 = <STDIN>;
chomp $choice1;
if ( $choice1 == 1 ) {
&acc_balance;
}
elsif ( $choice1 == 2 ) {
&acc_withdraw;
}
elsif ( $choice1 == 3 ) {
&acc_transfer;
}
else {
print "You entered an invalid option. Try again. \n";
goto ACC_CHOOSE;
}
return ();
}
我遇到的问题是当我尝试将 return 的 $acc_balance
值传递给其他子例程时。我试图在嵌套子例程下实现 return($acc_balance );
,但这只会提示我结束应用程序。所以基本上,我想做的是每次提款或转账时更新 $acc_balance
(它们目前在这段代码中是同一件事),但每当我尝试这样做时,它要么不'更新值,否则它只会显示经典的 "Press any key to continue..."
消息。
非常感谢任何帮助!谢谢!
看起来很可爱,但有些事情是不应该做的。我将尝试向您展示 选择 部分。
不要使用 &
调用子程序,而是使用括号,即 acc_choose();
而不是 &acc_choose;
。
不要在 perl 中嵌套 functions/subs。如果你真的想封装东西(我很欣赏并推荐), 使用模块。但这超出了这个问题的范围。稍后你会了解到。
如果不是绝对必要,请不要使用 goto
。它使控制流程变得怪异、难以遵循,并且经常导致意外。
如果你想重复某事 直到满足某个条件——或者换句话说——while某个条件没遇见,
使用 while
循环。
鉴于此,我建议 choose 部分(省略花哨的印刷):
sub acc_balance {
print "\nYour balance is: $acc_balance SEK\n\n";
}
sub acc_withdraw {
my $acc_balance_withdraw = 0;
do {
print "\nEnter how much you'd like to withdraw: \n";
$acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $acc_balance ) {
print "Insufficient funds.\n";
}
} while( $acc_balance_withdraw > $acc_balance );
# if you get here, then $acc_balance_withdraw <= $acc_balance, so:
$acc_balance -= $acc_balance_withdraw;
print "\nYour current balance is now: $acc_balance SEK\n\n";
}
# actually almost the same as acc_withdraw() only with
# other screen output and no `-=` operation
sub acc_transfer {
# left as an excercise
}
sub acc_choose {
print "[1] Account Balance\n";
print "[2] Withdraw\n";
print "[3] Transfer\n";
print "[4] Exit\n";
do {
my $choice1 = <STDIN>;
chomp $choice1;
if ( $choice1 == 1 ) {
acc_balance();
}
elsif ( $choice1 == 2 ) {
acc_withdraw();
}
elsif ( $choice1 == 3 ) {
acc_transfer();
}
elsif ( $choice1 == 4 ) {
print "Thank you. Good bye.\n"
}
else {
print "You entered an invalid option. Try again. \n";
}
} while( $choice != 1 && $choice != 2 && $choice != 3 && $choice != 4 );
}
您尝试的一个问题可能是您递归地调用了 acc_choose()
,即您是从其内部调用它。再加上goto
确实可以起到很好的娱乐效果。
祝你好运,继续加油。
哦,然后回答你的问题:现在拥有子例程 return 东西真的很简单。这不是必需的,因为你使用 $acc_balance
的全局变量(也不要这样做),但如果你愿意,你可以让 subs return 像这样的新余额:
sub acc_withdraw {
my $old_balance = shift; # that's the first argument given to this sub
my $acc_balance_withdraw = 0;
do {
print "\nEnter how much you'd like to withdraw: \n";
$acc_balance_withdraw = <STDIN>;
if ( $acc_balance_withdraw > $old_balance ) {
print "Insufficient funds.\n";
}
} while( $acc_balance_withdraw > $old_balance );
# if you get here, then $acc_balance_withdraw <= $acc_balance, so:
my $new_balance = $old_balance - $acc_balance_withdraw;
print "\nYour current balance is now: $new_balance SEK\n\n";
return $new_balance;
}
# and then...
$acc_balance = acc_withdraw($acc_balance);
我删除了格式和颜色,因为它与问题无关。方法如下:子例程需要的所有内容都来自其参数,它更改的所有内容都将返回。
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
sub create {
print << 'END_MSG';
Dear Sir or Madam,
We're very happy you've chose us as your bank.
Before we proceed, we need to set-up your account.
END_MSG
my ($firstname, $lastname);
my $first = 1;
while (! defined $firstname || ! defined $lastname
|| q() eq $firstname || q() eq $lastname
) {
say "You didn't fill in first or last name. Try again." unless $first;
undef $first;
print "\nYour first name: ";
chomp( $firstname = <STDIN> );
print "\nYour last name: ";
chomp( $lastname = <STDIN> );
}
say "Please wait while the system loads.\n";
say "\nWelcome ", $firstname, " ", $lastname, "!\n";
return ($firstname, $lastname)
}
sub choose {
my $balance = 2451.26;
my @menu = ( 'Account Balance',
'Withdraw',
'Transfer',
'Quit',
);
my $choice = q();
until ('4' eq $choice) {
for my $i (0 .. $#menu) {
say '[ ', $i + 1, ' ] ', $menu[$i];
}
chomp( $choice = <STDIN> );
my @actions = (\&balance,
\&withdraw,
\&transfer,
sub {}
);
my $action = $actions[$choice - 1];
if ($action) {
my $value = $action->($balance);
$balance = $value if defined $value;
} else {
say 'You entered an invalid option. Try again.';
}
}
}
sub balance {
my $balance = shift;
say "\nYour balance is: $balance SEK\n\n";
return $balance
}
sub withdraw {
my $balance = remove('withdraw', @_);
return $balance
}
sub transfer {
my $balance = remove('transfer', @_);
return $balance
}
sub remove {
my ($action, $balance) = @_;
say "\nEnter how much you'd like to $action:\n";
my $remove = <STDIN>;
if ( $remove > $balance ) {
print "Insufficient funds.";
} else {
$balance -= $remove;
}
balance($balance);
}
my ($firstname, $lastname) = create();
choose();
say "Good bye, $firstname $lastname!";
嵌套子程序的嵌套方式与 Pascal 不同。事实上,您不能在 Perl 中嵌套命名子例程。
如图所示,只有在需要引用子例程时才使用&
。
不要使用 goto
。循环更容易理解和管理。
此外,请确保不要在打印重要消息后立即擦除屏幕 ("Insufficient funds")。
我认为您不应该为这项作业使用子例程。但令我担心的是,有人告诉您在调用子例程时要使用 & 符号 &
,并解释了如何使用标签和 goto
。这不适合现代计算机语言,您可以做得更好
例如,我会这样写你的子程序acc_create
sub acc_create {
while () {
print "\nYour first name: ";
chomp (my $firstname = <STDIN>);
print "\nYour last name: ";
chomp (my $lastname = <STDIN>);
last if $firstname and $lastname;
print "You didn't fill in first or last name. Try again.\n";
}
print "Please wait while the system loads.\n\n";
print
$clr_scr,
color('green'), $atm->center("ATM v. 1.20"), color('reset');
print "\nWelcome $firstname $lastname!\n\n";
}
我还有很多话要说,但 Stack Overflow 不是教程的地方