我对Perl中的标量有一些基本的问题。我读到的一切都说标量有一个值:
标量可以包含三个不同中的任何一个的单个值 flavor:数字,字符串或引用。虽然标量可能不会 直接保存多个值,它可能包含对数组的引用 或者哈希,而哈希又包含多个值。
- 来自perldoc
很好奇下面的代码是如何工作的
open( $IN, "<", "phonebook.txt" )
or die "Cannot open the file\n";
while ( my $line = <$IN> ) {
chomp($line);
my ( $name, $area, $phone ) = split /\|/, $line;
print "$name $phone $phone\n";
}
close $IN;
只是为了澄清上面的代码是用以下格式打开一个管道分隔的文本文件name|areacode|phone
它打开文件,然后将它们分成$name $area $phone
;它如何通过文件的多行并打印出来?
回到上面的perldoc引用&#34;标量可能包含字符串,数字,引用的单个值。&#34; 我假设它必须是参考,但它甚至看起来不像是一个参考,如果它看起来像是标量的参考?所以我想知道内部会发生什么让Perl迭代代码中的所有行?
没什么紧急的,只是我注意到并且很好奇。感谢。
答案 0 :(得分:2)
看起来Borodin对你想要的部分进行了调整,但我会加入它。
有变量,为我们存储东西,还有运营商,为我们做事。文件句柄,$IN
中的文件句柄,不是文件本身或文件中的数据。它是程序用来从文件中获取信息的连接。
当你使用行输入操作符<>
时,你给它一个文件句柄,告诉它从哪里抓取下一行。它本身默认为ARGV
,但您可以在其中放置任何文件句柄。在这种情况下,您有<$IN>
。鲍罗丁已经解释了参考和裸字的内容。
因此,当您使用行输入操作符时,它会查看您提供的连接,然后从该文件中获取一行并返回它。您可以使用它的函数形式更轻松地理解它:
my $line = readline( $IN );
你得到的东西不是来自$IN
,而是它指向的东西。在此过程中,$IN
会跟踪文件中的位置。请参阅seek
和tell
。
沿着同样的路线是Perl的正则表达式。许多人称/foo.*bar/
为正则表达式。他们有点不对劲。模式匹配运算符//
中有一个正则表达式。模式是指令,但在操作员使用它之前它不会自行执行任何操作。
我在课堂上发现,如果我强调语法的名词和动词部分之间的区别,人们可以更容易地使用这种东西。
旧答案
通过while
循环的每次迭代,只有一个值被放入标量变量中。当循环完成一行时,一切都会重置。
$line
中的值是单个值:尚未分解的整行。 Perl并不关心单个值是什么样的。每次迭代,你只处理一行,这就是$line
中的内容。请记住,这些是变量,这意味着您可以修改和替换它们的值,因此它们一次只能容纳一件事,但可以有多次。
标量$name
,$area
和$phone
具有单个值,每个值由split
生成。这些是词法变量(my
),因此它们仅在定义它们的特定循环迭代中可见。
除此之外,我不确定你可能会对哪个标量感到困惑。
答案 1 :(得分:1)
打开文件的老式方法是使用文件句柄的裸名称,如此
open IN, 'phonebook.txt'
文件句柄是一种特殊类型的值,如标量,散列,数组等,但它没有前缀符号来区分它。 (这实际上并不是事实的全部,但如果我添加更多细节,我担心会让你感到困惑。)
Perl仍然可以这样工作,但最好避免出于几个原因。
所有此类文件句柄都是全局,并且无法通过范围限制对它们的访问
无法将值传递给子例程或将其存储在数据结构中
因此几年前Perl得到了增强,因此您可以使用引用来处理句柄。它们可以存储在标量变量,数组或散列中,也可以作为子程序参数传递。
当你写
时会发生什么open my $in, '<', 'phonebook.txt'
是perl 自动生成 匿名文件句柄,并在变量$in
中添加对它的引用,所以是的,你是对的,它是是参考。 (同时改变的另一件事是转移到三参数open
调用,它允许您打开一个名为>.txt
的文件进行输入。)
我希望这有助于你理解。这是一个不必要的细节,但它通常可以帮助你记住Perl理解底层细节的方式。
顺便提一下,最好保留词汇变量的小写字母,即使对于文件句柄引用也是如此。我经常在末尾添加fh
来表示该变量包含文件句柄,如$in_fh
。但是没有必要使用资本,这些资本通常保留给Package::Names
这样的全局变量。
更新 - 故事的其余部分
我认为我应该添加一些东西来解释我所说的内容,因为害怕误导那些关心血腥细节的人。
Perl保留一个符号表哈希 - 一个 stash - 它的工作方式与普通的Perl哈希一样。每个包都有一个这样的存储,包括默认包main
。请注意,此哈希与词法变量无关 - 使用 my 声明 - 它们完全分开存储。
stashes的Ther索引是包变量的名称,没有初始符号。所以,例如,如果你有
our $val;
our @val;
our %val;
然后存储将只有一个单个元素,键为val
,值为对 typeglob 的中间结构的引用。这是另一个哈希结构,其中一个元素用于已声明的每个不同类型的变量。在这种情况下,我们的val
typeglob将包含三个元素,分别用于标量,数组和散列变种{{1变量。
其中一个元素也可能是 IO 变量类型,这是保存文件句柄的位置。但是,由于历史原因,作为文件句柄传递的值实际上是对包含它的typeglob的引用。这就是为什么,如果你写val
然后open my $in, '<', 'phonebook.txt'
,你会看到类似print $in
的内容 - GLOB(0x269581c)
是 typeglob 的缩写。
除此之外,上述帐户是准确的。 Perl在当前包中自动生成匿名 typeglob ,并仅将 IO 插槽用于文件句柄。
答案 2 :(得分:-2)
while
循环的条件总是标量。在标量上下文中,<>
运算符从给定的文件句柄中读取单行(这是一个字符串,因此是标量)。 while
只是一直调用它,直到<>
的结果为假。
如果您想在列表上下文中使用<>
,则必须使用for
,而不是while
。
答案 3 :(得分:-2)
Perl中的标量用$表示,它们确实可以包含您在问题中提到的值的类型,但旁边它们也可以包含文件句柄。您可以通过两种方式在Perl中创建文件句柄,一种方式是Lexical
open my $filehandle, '>', '/path/to/file' or die $!;
另一个是全球
open FILEHANDLE, '>', '/path/to/file' or die $!;
你应该使用你正在做的Lexical版本。
代码中的while
循环使用词法文件句柄上的<>
运算符,每次调用时都会从文件中返回一行,直到它超出行(当达到文件结尾时) )在这种情况下,它返回false。
我对文件句柄有了更多细节,因为它似乎是一个你不完全清楚的概念。