当前位置: 首页 > 知识库问答 >
问题:

为什么Perl允许在没有定义的情况下声明函数?

锺超英
2023-03-14

Perl有一个未定义函数的概念。已声明但未定义的函数。

sub foo;
foo(); # Undefined subroutine error
bar(); # Undefined subroutine error

这个函数foo现在存在于符号表中,它可以用来解析方法调用。但是为什么这个“特征”会存在呢?在C语言中,这是因为函数是类型检查的,有时您希望在定义之前进行调用(例如解决循环依赖关系)。但是Perl没有这样的特性,所有的函数符号都是在运行时而不是编译时解析的。

>

如果不是原型,为什么它会存在?

为什么在方法解析中使用未定义的子程序?为什么不完全忽略它们呢?你不能调用它们,就我所知(最多)它们是内部实现细节?这就是为什么如果函数没有定义,我们就不能继续方法解析,就好像它不存在一样(看起来就不那么令人困惑了)。

共有3个答案

微生俊
2023-03-14

这为我节省了很多调试

sub AUTOLOAD
{
   my (undef,$filename,$lineno) = caller;
   my ($fn) = basename($filename);

   logmsg('E',"Undefined reference ($fn/$lineno): ref=$AUTOLOAD, refer=$ENV{HTTP_REFERER}");
}
濮俊美
2023-03-14

我想说,这和其他类型的人一样;只是它如何被解析的产物。

my $hr = { a => 1 };   # $hr name introduced at compile time, assigned or not 

所以也一样

sub name { ... };      # "name" "declared" at compile time

只说子名字与“我的$hr”差不多 --然后有一个没有定义的符号。

我不知道解析器是如何工作的,但我猜它必须先使用子名称,然后再“绑定”定义,因此偶然情况下,我们也可以只说子名称 并具有该名称。

我的意思是说,这是“原因”,根据“但是为什么这个“特征”会存在?”

但是,一旦编译器提前知道有一个子系统具有该名称,那么这个事实可能会有各种用途。

柴星津
2023-03-14

这是关于原型的,函数的声明(或不声明)在编译时确实有影响。考虑

  1.  print foo + 42;
    

    单独来看,这相当于print('foo'42)-foo是一个“空话”。如果您启用了严格的'subs',它会给您一个编译错误,告诉您禁止使用裸字。

     sub foo;
     print foo + 42;
    

    这相当于打印(foo(42));编译器知道foo是一个子系统,它没有原型,因此它以“list op”的方式消耗它之后的所有内容,然后是术语42

     sub foo();
     print foo + 42;
    

    这相当于打印(foo()42);编译器知道foo有一个原型,它不带任何参数,因此不会查找任何参数,foo42将是运算符的操作数。

     sub foo($);
     print foo + 42;
    

    与案例2类似,这相当于打印(foo(42))。我想可能有一个测试我可以用来区分他们。

    重要的是,sub是否已知在编译时都会产生影响,Perl为您提供了在定义sub主体之前声明该事实的选项,尽管它可能很少需要。

    至于为什么它会影响方法解析顺序——很可能是副作用,但这并没有错。前向声明sub意味着您打算在编译完成之前提供定义。如果不这样做,那么在尝试调用它时将出现运行时错误。在我看来,如果这样的声明在MRO中的一个包中,那么这意味着“这里应该有一个方法,但我忘记了”,在MRO到达该包时,您会收到一个错误。

 类似资料:
  • 最近为什么const对象需要用户提供的默认构造函数?被标记为为什么C需要用户提供的默认构造函数来默认构造const对象?。我正在使用coliru和rextexter来测试各种版本的gcc(g-4.7、g-4.8、g-4.9)和clang(3.4和3.5),以查看此行为是否在较新版本的编译器中引入。这里我们有两个测试用例,分别来自两个问题: 和: 叮当出错: 预期但不是gcc,也不是MSVC。我想我

  • 问题内容: 我可以用修饰符声明以下程序包,但似乎对任何内容都没有影响: 所以我的问题是,在程序包清算之前添加修饰符会做什么,为什么编译器会允许它? 更新 :似乎与Eclipse捆绑在一起的编译器是一个问题,就像其他人提到的那样,这是使用Sun的JDK的编译器错误。 问题答案: 他们不是。您正在使用哪个编译器?

  • 在这里,我们希望收件人重定向我们的网站(endpoint与唱staus的文档),但从API文档,我们没有得到任何可行的解决方案。 是否有任何方法重定向收件人后唱的文件(不使用客户端用户ID或从电子邮件)?

  • 问题内容: 作为ASP.NET MVC 2 Beta 2更新的一部分,默认情况下不允许JSON GET请求。看来您需要将字段设置为从控制器返回对象之前。 这背后的原因是什么?如果我正在使用JSON GET尝试进行一些远程验证,那么我应该使用其他技术吗? 问题答案: DenyGet默认的原因是在MSDN上,该链接提供了Phil Haack的博客 的详细信息。看起来像跨站点脚本漏洞。

  • 考虑以下代码: 这里无论有什么值,

  • 我正在从文档中学习反应,但不确定在这个例子中超级()做什么。通常,它不需要传递给创建新实例的参数,然后调用React吗?组件的构造函数方法将这些参数合并到实例中?没有任何争论它是做什么的?