アプリ版:「スタンプのみでお礼する」機能のリリースについて

myとourの違いが、飲み込めません。
以下、当方の環境とします。

【コード(1) ファイル名は read.pl とする】
#!/bin/perl

use strict;
use warnings;

my @filelist = <abc*.log>;

foreach my $i (0 .. $#filelist){

open(IN, "$filelist[$i]");
my @alltxt = <IN>;


sub f_readlines {
my $export=0;
foreach my $strings(@alltxt){
$export .= $strings;
}

return $export;

}


【コードの説明と前提】
これは、read.plを実行すると、同じディレクトリにある、「abcで始まり .logで終わるファイル」のすべてを引数として、
同じ処理を繰り返すコードです。
実行時のカレントディレクトリには、abc001.log、abc002.log、abc003.logという3つのファイルが存在します。

abc001.log には aaaaaaa という文字列が書き込まれています。
abc002.log には bbbbbbb という文字列が書き込まれています。
abc003.log には ccccccc という文字列が書き込まれています。


【コード(1)の実行結果】
$ ./read.pl
aaaaaaa

aaaaaaa

aaaaaaa


【現状と当方の考え】
このコードの本来の目的は、存在するファイルの数だけ、その中身を順次読みだす、というものです。
ですので、コード(1)の実行結果は

$ ./read.pl
aaaaaaa

bbbbbbb

ccccccc


になってくれないといけないのです。

しかし、

my @alltxt = <IN>;

の行を

our @alltxt = <IN>;

に書き換えると、うまくいきました。

ネットを見ていると、myはスコープの範囲が限定的で、ローカルな変数のようで、
グローバル(どこでも変数として取り出せる)なものが our、というように読み取れます。

foreach の処理の中で宣言した my @alltxt ですから、
ファイルの数だけ、毎回 @alltxt の中身の値は変わるはずです。
それが、変わってくれず、初回に@alltxtに読み込んだ aaaaaaa だけが、ファイルの数だけ
出力されてしまいます。


【質問したいこと】
(1)myを使って代入した変数の中身は、同じスコープ内で作成した関数からは読みだせないのか?

(2)それならば、なぜ初回のaaaaaaaは、読み出せているのか?


以上よろしくお願いします。

A 回答 (2件)

あ, #1 は完全に勘違いしてた. ということで最初からやり直し.



まず, my を使うと「そこを通るたびに違う変数を作る」と思っていい. つまり, 今の場合 foreach で回す 3つのファイルのそれぞれに対して @alltxt が存在する. それに対して, サブルーチン f_readlines は 1つだけ存在し, その中では「最初の @alltxt」だけがアクセスできる. その結果「初回に@alltxtに読み込んだ aaaaaaa だけが、ファイルの数だけ出力されてしまいます」という結果になっている (2つ目以降では「ファイルから読み込んだ値を保持する @alltxt」と「f_readlines からアクセスする @alltxt」が別個に存在する).

一方 our は「(必要ならグローバルな変数を作って) それを現在のスコープに導入する」という働きになる. だから my の代わりに our を使うと @alltxt は 1つだけ存在し, それをサブルーチン f_readlines がアクセスするので期待通りの動作になる.

ちなみに勘違いのもとは, どうも foreach でまわす変数だけは扱いが違うっぽいところ.
    • good
    • 0

Perl のサブルーチンは基本的にファイルスコープでしか作れない. だから, そのプログラムは


#!/bin/perl

use strict;
use warnings;

my @filelist = <abc*.log>;

sub f_readlines {
my $export=0;
foreach my $strings(@alltxt){
$export .= $strings;
}

return $export;

}
foreach my $i (0 .. $#filelist){

open(IN, "$filelist[$i]");
my @alltxt = <IN>;
# 以下の詳細は不明
と書いたのと同じことになる.

というのが (1) の答え. (2) については完全なプログラムが提示されていないので不明.
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!