关于Print语句为什么那么写的讨论

关于Print语句为什么那么写的讨论

关于Print语句为什么那么写的讨论

flw 15:12:01
和你交流一个 Perl 5 的问题。
飞云Hoowa 15:11:09
说啊
flw 15:14:21
Perl 的语法非常灵活,但是掌握之后却觉得又很严谨,回想自己当初学 Perl,我觉得是很多 Perl 教材的作者没有吃透 Perl 的语法,解释不清楚,所以才觉得 Perl 不可捉摸。
飞云Hoowa 15:12:42

flw 15:14:34
我跟你举个例子。
飞云Hoowa 15:12:49
怎么下起定义了
flw 15:14:48
print "Hello, world\!n";
flw 15:15:24
如果你要望文件句柄中写,就得写作 print FH "Hello, world!\n";
飞云Hoowa 15:14:02
对啊
flw 15:15:54
我一直都搞不清楚,为什么 FH 和后面的 "Hello, world!\n" 之间不能有逗号。
飞云Hoowa 15:14:31
我也没研究过为什么
flw 15:16:25
而且,print 这个函数凭什么知道我是要望 FH 里边写,还是望屏幕上写。
飞云Hoowa 15:14:55
print STDERR "hello world"也可以
flw 15:16:49
换句话说,它凭什么把 FH 当作是要输出的目标,而不是来源?
飞云Hoowa 15:15:05
这个不知道
flw 15:17:02
可是我知道。
flw 15:17:08
我刚才才弄明白。
飞云Hoowa 15:15:22
还可以这样open(STDERR,">>error.log");
flw 15:17:55
你知道可以这样,这没错,可是你知道为什么可以这样吗?
flw 15:18:29
如果你搞不清楚为什么,那么别人向你学习的时候,对 Perl 的印象只能是觉得“不可捉摸”。
flw 15:18:38
我今天搞明白了。print "Hello, world!\n" 中的 print 和 print FH "Hello, world!\n" 中的 print 不是同一个东西。
飞云Hoowa 15:16:54
啊?
飞云Hoowa 15:17:10
听着好象很有意思,你继续说
flw 15:19:17
前面的是一个 sub,而后面的是一个类的方法,也就是 IO::Handle->print
flw 15:19:46
只能这么解释,这样才能解释得通。
飞云Hoowa 15:18:07
你的意思,print FH是,调用了print子程序,然后FH是参数?
flw 15:20:38
Perl 5 有这样一条语法:类的方法可以用 method object args 这样的形式来调用。
flw 15:20:53
这和 object->method args 是等效的。
flw 15:21:09
这就是 FH 后面为什么不能有逗号的原因。
flw 15:21:55
飞云Hoowa 15:18:07
你的意思,print FH是,调用了print子程序,然后FH是参数?

我的意思恰恰不是这样,我的意思是说,FH 是个对象,print 是它的方法。
flw 15:22:55
再往下继续说,print FH "Hello", "world" 和 print FH ("hello", "world") 还有 FH->print( "hello", "world" ) 都是等效的。
飞云Hoowa 15:21:09
这个......我需要仔细想想。没这么分析过
flw 15:23:36
如果其中一个有语法错误(比如 hello 和 world 之间忘了写逗号),那么另外两个也都是有语法错误的。
飞云Hoowa 15:22:18
oh
flw 15:24:34
只有这样才解释得通。
flw 15:24:41
类似的语法还有很多。
flw 15:24:56
凡是看起来奇怪的语法,其实都是有语法条文的。
flw 15:25:14
只不过表现的形式可能比较怪异。
飞云Hoowa 15:23:34
你这个是自己猜的还是看资料里找的啊
flw 15:25:31
我自己猜的。
flw 15:25:37
而且必然是这样的。
不是这么回事,...
不是这么回事,Perl5里面内置print加filehandle不能用逗号只是人为规定,跟Perl5里的对象方法什么的扯不上关系。你从源代码里就能看出来,摘抄如下(ActivePerl 5.8.6.811 Source):
toke.c第4699行起是对print关键字的词法处理
...
case KEY_print:
checkcomma(s,PL_tokenbuf,"filehandle");
LOP(OP_PRINT,XREF);
case KEY_printf:
...
其中checkcomma就是S_checkcomma的宏定义,它检查了一些语法错误,其中就包括filehandle后面带逗号这种情况:
toke.c第6038行起
...
if(*s==',') {
int kw;
*s='\0';
kw=keyword(w,s-w)||get_cv(w,FALSE)!=0;
*s=',';
if(kw)
return;
Perl_croak(aTHX_ "No comma allowed after %s", what);
}
...
而且内置的FILEHANDLE类型也不是类,随便对一个句柄用ref看一下就知道了。这个语法perldoc perlfunc里也写明白了,既然flw想一切以语法条文为准,有这个应该就满足了吧。
楼上说的确实有...
楼上说的确实有道理,我看到 print FH, "hello" 的出错信息中,也有 HANDLE 后面不能带逗号的字样.

只不过, FH->print( "Hello" ) 这样的写法可以成功又不知道该怎么解释?
这种写法只有载...
这种写法只有载入IO::Handle模块或者它的派生模块以后才能成功吧,实际上FH->print("Hello")就是IO::Handle::print(FH,"Hello"),而IO::Handle::print函数则只是内置print的一个简单包装而已。在IO::Handle模块文档最后的BUGS一节中说明了这种写法能成功的原因,大意是Perl5为了和以前的版本保持兼容,专门使得文件句柄表现得像一个IO::Handle类的对象,但它们实际上并不是对象,只是占用了IO::Handle这个名字空间而已。验证这个说法的程序也很简单:
open(FH,">x.tmp") or die;
FH->print("Hello");
package IO::Handle;
sub print
{
my $fh=shift;
print ref($fh),"\n";
print "want to output '@_'\n";
}
根据运行结果可知传递过来的参数只是一个GLOB引用,和任何类都没有关联。
受教了!--多...
受教了!
多谢 chaoslawful!