从嵌套子例程Perl返回值

从嵌套子例程Perl返回值,perl,nested,subroutine,Perl,Nested,Subroutine,我们收到了学校的一份作业,我们应该在那里制作自己的小型n'简单Perl应用程序。我想我应该做一个自动取款机模拟器。到目前为止,一切进展顺利;我使用子程序创建了一个菜单(提取、平衡、转移)。这是我目前的代码: #! /usr/bin/perl #Written by: Tobias Svenblad, h15tobsv@du.se, Digitalbrott & e-Säkerhetsprogrammet (2015) #PerlLab03-2c.plx use warnings; us

我们收到了学校的一份作业,我们应该在那里制作自己的小型n'简单Perl应用程序。我想我应该做一个自动取款机模拟器。到目前为止,一切进展顺利;我使用子程序创建了一个菜单(提取、平衡、转移)。这是我目前的代码:

#! /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( "", ( "\033[2J", "\033[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 ();
}
#/usr/bin/perl
#作者:Tobias Svenblad,h15tobsv@du.se,Digitalbrott&e-Säkerhetsprogrammet(2015年)
#PerlLab03-2c.plx
使用警告;
严格使用;
使用术语:ANSIColor;
使用文本::格式;
我的名字;
我的姓;
我的$acc_余额=2451.26;
我的$acc_提款;
my$clr_scr=join(“,(“\033[2J”,“\033[0;0H”);#此变量将清除屏幕并跳转到位置0,0。
my$atm=Text::Format->new;
打印颜色(“绿色”);
打印$atm->center(“atm v.1.20”);
打印颜色(“重置”);
#创建帐户消息。
我的$crt_acc_msg=中心(“ATM v.1.20”);
打印颜色(“重置”);
打印“\n您的余额为:”;
打印颜色(“绿色”);
打印$acc_余额;
打印颜色(“重置”);
打印“SEK\n\n”;
&acc_选择;
}
副行政长官撤回{
输入金额:
打印$clr\U scr;
打印颜色(“绿色”);
打印$atm->center(“atm v.1.20”);
打印颜色(“重置”);
打印“\n输入您要提取的金额:\n”;
我的$acc_余额_取款=;
如果($acc\U余额\U提取>$acc\U余额){
打印“资金不足”;
转到输入金额;
}
$acc\U balance-=$acc\U balance\U DROW;
打印“\n当前余额为:”;
打印颜色(“绿色”);
打印$acc_余额;
打印颜色(“重置”);
打印“SEK\n\n”;
&acc_选择;
}
次级会计转帐{
输入金额:
打印$clr\U scr;
打印颜色(“绿色”);
打印$atm->center(“atm v.1.20”);
打印颜色(“重置”);
打印“\n输入您要转账的金额:\n”;
我的$acc_余额_取款=;
如果($acc\U余额\U提取>$acc\U余额){
打印“资金不足”;
转到输入金额;
}
打印“\n当前余额为:”;
打印颜色(“绿色”);
打印$acc\U余额-$acc\U余额\U支取;
打印颜色(“重置”);
打印“SEK\n\n”;
&acc_选择;
}
ACC_选择:
打印“[”;
打印颜色(“青色”);
打印“1”;
打印颜色(“重置”);
打印“]”;
打印“帐户余额\n”;
打印“[”;
打印颜色(“青色”);
打印“2”;
打印颜色(“重置”);
打印“]”;
打印“撤回”\n;
打印“[”;
打印颜色(“青色”);
打印“3”;
打印颜色(“重置”);
打印“]”;
打印“传输”\n;
我的$choice1=;
chomp$choice1;
如果($choice1==1){
&acc_余额;
}
elsif($choice1==2){
&acc_撤回;
}
elsif($choice1==3){
&acc_转移;
}
否则{
打印“您输入的选项无效。请重试。\n”;
转到ACC_选择;
}
返回();
}
我面临的问题是当我尝试将
$acc\u balance
值返回到其他子例程时。我尝试实现
返回($acc\u balance)
在嵌套的子例程下面,但这只会提示我结束应用程序。因此,基本上,我要做的是在每次提取或转账时更新
$acc\u balance
(它们目前在该代码中是相同的),但每当我尝试这样做时,它要么不更新值,要么只显示经典的
“按任意键继续…”
消息


非常感谢您的帮助!谢谢!

看起来很可爱,但有些事情是您不应该做的。我将试着向您展示“选择”部分

不要使用
&
调用子例程,而是使用括号,即
acc\u choose()
而不是
&acc\u choose;

不要在perl中嵌套函数/子函数, 使用模块。但这超出了本问题的范围。稍后您将了解这一点

如果不是绝对必要的话,不要使用
goto
。这会使控制流变得怪异、难以遵循,并经常导致意外

如果你想重复某件事直到满足某个条件,或者换句话说,当某个条件不满足时, 在循环时使用

考虑到这一点,我建议对choose部分采用类似的方式(花式打印省略):


看起来很可爱,但有些事情你不应该做。我会试着让你看看选择部分

不要使用
&
调用子例程,而是使用括号,即
acc\u choose()
而不是
&acc\u choose;

不要在perl中嵌套函数/子函数, 使用模块。但这超出了本问题的范围。稍后您将了解这一点

如果不是绝对必要的话,不要使用
goto
。这会使控制流变得怪异、难以遵循,并经常导致意外

如果你想重复某件事直到满足某个条件,或者换句话说,当某个条件不满足时, 在循环时使用

考虑到这一点,我建议对choose部分采用类似的方式(花式打印省略):


我删除了格式和颜色,因为这与问题无关。下面是如何做到的:子例程需要从其参数中获取的所有内容,它更改的所有内容都将返回

#! /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!";
!/usr/bin/perl
使用警告;
严格使用;
使用特征qw{say};
子创建{
印刷(结余美元);
$balance=$value(如果定义为$value);
}否则{
说“您输入的选项无效。请重试。”;
}
}
}
次级余额{
我的$balance=shift;
说“\n您的余额是:$balance SEK\n\n”;
返回$balance
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!";
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";
}