3

都市が設定された配列があります。サブルーチンへの参照によって配列を渡し、各都市を出力して出力したいと考えています。ただし、次の問題があります。

  1. サブルーチンのwhileループの前に各要素にアクセスできます。しかし、 whileループ内の要素にアクセスできません。エラーメッセージが表示されます:

    ... 44 行目、997 行目 (#1) の印字で初期化されていない値が使用されています 44 行目、998 行目 (#1) の印字で初期化されていない値が使用されています ...

以下はいくつかのコードです。何が印刷され、何が印刷されないかについてコメントしました(説明に必要のないコードを切り取ろうとしました...):

@cities;

# Assume cities is loaded successfully
&loadCities(getFileHandle('cities.txt'), $NUM_CITIES, \@cities);
&printElements(getFileHandle('names.txt'), \@cities);

sub printElements{

    my $counter = 0;
    my $arraySize = scalar $_[1];

    # Prints fine!!!
    print @{$_[1][($counter)%$arraySize];

    while ((my $line = $_[0]->getline()) && $counter < 1000){

        # Doesn't print. Generates the above error
        print @{$_[1][($counter)%$arraySize];

        $counter += 1;
    }
}
  1. Perl の構文は、私を非常に混乱させます。@{$_[1]}[0] で何が起こっているのかわかりません。私はそれを解決しようとしています。
  1. $_[1]、この位置の値をスカラー値 (配列のメモリ アドレス) として扱います
  2. @{...}、このメモリアドレスに格納されているものを配列として解釈します
  3. @{...} [x]、インデックス x の要素にアクセス

私は正しい軌道に乗っていますか?

4

5 に答える 5

3

参照をもう少し理解しやすくするために、私->は munge-it-all-together 構文よりも構文を好みます。

それ以外の:

@{$_[1]}[0].

試す

$_[1]->[0];

それは同じことを意味します。より簡単に、より見やすくなりました。$_[1]これは配列参照であり、その配列参照の最初の要素を参照していることがわかります。

ただし、より良い方法は、さまざまな要素の変数を単純に設定することです@_。さらにいくつかの文字を入力する必要がありますが、コードははるかに理解しやすく、デバッグもはるかに簡単です。

sub print_elements {
    my $file_handle      = shift;   # This isn't a "reference", but an actual file handle
    my $cities_array_ref = shift;   # This is a reference to your array

    my @cities = @{ $cities_array_ref };  # Dereferencing makes it easier to do your program

今、あなたのサブルーチンは名前を持つ変数を扱っており、配列参照は物事をよりきれいにする配列です。また、メイン プログラムの値に誤って影響を与えることもありません。を使用する@_と、渡した値への直接リンクになります。変更@_すると、おそらくやりたいことではないメイン プログラムの値が変更されます。

したがって、サブルーチンを実行します。

sub printElements {
    my file_handle        = shift;
     my $cities_array_ref  = shift;

    my @cities = @{ $cities_array_ref };
    my $counter;
    my $array_size = @cities;     # No need for scalar. This is automatic
    while  ( my $line = $file_handle->getline and $counter < 1000 ) {
        chomp $line;
        my $city_number = $counter % $array_size;
        print $cities[$city_number]. "\n";
        $counter += 1;
    }
}

すべてを詰め込もうとするのではなく、いくつかの変数を割り当てるだけで、何が起こっているのかを簡単に確認できることに注意してください。サブルーチンへのパラメーターがどうあるべきかを簡単に確認できます。間違ったパラメーター順序でサブルーチンを呼び出した場合は、簡単に見つけることができます。また、私が勃発して$counter % $array_sizeそれを変数に割り当てたことにも注意してください。突然、私がそこから何を得ようとしているのかが明らかになりました。

$lineただし、取得している をどこで使用しているのかわかりませんgetline。私は何か見落としてますか?

ちなみに、whileループ内で配列を参照せずにこれを行うこともできました。

sub printElements {
    my file_handle        = shift;
    my $cities            = shift;   # This is an array reference!

    my $counter;
    my $array_size = @{ $cities };   # I need to deref to get an array
    while  ( my $line = $file_handle->getline and $counter < 1000 ) {
        chomp $line;
        my $city_number = $counter % $array_size;
        print $cities->[$city_number]. "\n";   # That's it!
        $counter += 1;
    }
}

この構文を使用すると、配列を指す参照である->ことを簡単に確認できます。$citiesよりもはるかにクリーンで理解しやすい${$cities}[$city_number]

于 2014-02-23T23:29:33.813 に答える
0

参考文献も私を混乱させます!私はいつもそれらをできるだけ早く逆参照したいと思っています。これは私のために働く:

sub printElements{

    my $counter = 0;
    my $fh = $_[0];
    my @array = @{$_[1]};
    my $arraySize = scalar @array;

    # Prints fine!!!
    print @array[($counter)%$arraySize];

    while ((my $line = $fh->getline()) && $counter < 1000){

        #Doesn't print. Generates the above error
        print @array[($counter)%$arraySize];

        $counter += 1;
    }
}

他の誰かがコメントで、参照を使用する方が良い方法だと思う理由を説明できると思いますが (そうしてください)、「シンプルに保つ」というマントラの下で、私は彼らと一緒に作業するのは好きではありません。おそらく、私は C プログラマーではなかったからでしょう...

于 2014-02-23T22:27:39.057 に答える