我如何在 Perl 6 中的 class 中的子例程上调用 .WHY?

How can I call .WHY on a subroutine in a class in Perl 6?

调用 .WHY 声明 returns 围绕它构建的特殊注释。这很酷。如何引用 class 中定义的子例程?它总是隐藏的吗?我很好奇提供子例程而不是 classes 的模块(答案可能是 "don't do it that way")。我主要是在玩弄 .WHY 的极限以及我能走多远。

#| This is the outside bit
sub outside { 137 }
put &outside.WHY; # This works

#| Class Foo is an example
class Foo {
    #| The bar method returns a number
    method bar { 137 }

    #| quux is a submethod
    submethod quux { 137 }

    #| qux is private
    submethod !qux { 137 }

    #| The baz method also returns a number
    sub baz { 37 }

    put &baz.WHY; # this works in this scope
    }

put "---- With an object";
quietly {
    my $object = Foo.new;
    put "As object: ", $object.WHY;

    # sub is not really a method?
    put "As object - bar: ", $object.^find_method( 'bar' ).WHY;

    # should this work? It *is* private after all
    put "As object - qux: ", $object.^find_method( 'qux' ).WHY;
    }

put "---- With class name";
quietly {
    put Foo.WHY;
    put "As class lookup: ", ::("Foo").WHY;
    put "As class lookup (quux): " ~  Foo.^lookup( 'quux' ).WHY;
    put "As class lookup (baz): " ~  Foo.^lookup( 'baz' ).WHY;  # nope!

    # this is the part where I need help
    put "As :: lookup: ", ::("Foo")::("&baz").WHY; #nope
    }

这是输出:

This is the outside bit
The baz method also returns a number
---- With an object
As object: Class Foo is an example
As object - bar: The bar method returns a number
As object - qux:
---- With class name
Class Foo is an example
As class lookup: Class Foo is an example
As class lookup (quux): quux is a submethod
As class lookup (baz):
As :: lookup:

这是我要问的最后一行输出。如何进入 class 中定义的子例程?

这只是工作中的词法范围:

Subs 默认为 my,所以如果你想从外部获取它们,你必须添加一个 our(或以其他方式手动公开它们 - 据我所知我知道,没有内置方法可以通过 MOP 或其他元编程功能(如 MY:: 伪包)获取它们。

I'm curious about modules that provide subroutines instead of classes

这就是 is export 的目的。

    # should this work? It *is* private after all
    put "As object - qux: ", $object.^find_method( 'qux' ).WHY;

以下两项工作:

put "As object - qux: ", $object.^find_private_method('qux').WHY;
put "As object - qux: ", $object.^private_method_table<qux>.WHY;

(find_private_method 似乎没有在 p6doc 中记录,所以我不确定它是否是官方的 API。 private_method_table 有记录,虽然没有真正解释。 )


    # this is the part where I need help
    put "As :: lookup: ", ::("Foo")::("&baz").WHY; #nope

如果您将 sub baz { 37 } 声明为 our sub baz { 37 },则此方法有效。
您还可以更简单地编写查找:

put "As :: lookup: ", &Foo::baz.WHY;

our 声明符(在 Synopsis 3, section "Declarators" 中解释)将符号与当前包相关联——在本例中为 class——以便可以从包外部访问它使用 :: 语法。

默认情况下,子例程是词法范围的——即它们的默认声明符,如果指定了 none,则为 my。 (语句 sub baz { 37 } 基本上 1 与在花括号分隔范围的顶部写入 [​​=20=] 相同的效果。)
通过编写 our sub baz { 37 },您告诉它使用 our 而不是 my 范围。


I'm curious about modules that provide subroutines instead of classes

要么用 our 声明它,如上所示 (在这种情况下,用户范围将必须使用完全限定名称 Foo::baz,或者将其导出到用户范围 (在这种情况下,他们可以将其称为 baz.

使符号可导出的最简单方法是使用 is export 特性:

module Foo {
    #| The baz method also returns a number
    sub baz is export(:ALL) { 37 }
}

import Foo :ALL;

say &baz.WHY;

A use 语句隐式调用了相关模块上的 import。由于这里的模块定义在同一个文件中,我们可以直接调用import。

请注意,您也可以编写 sub baz is export { 37 }(不带 :ALL),在这种情况下,只要 class 为 use,就会默认导入该符号' d 或 import'ed。但在 Perl 5 / CPAN 社区中,这被认为是不好的做法,建议让用户导入单个符号。在 Perl 6 中,导入单个符号还不起作用,所以我建议现在使用 :ALL 标签。


1) 我知道的唯一区别是,在第一种情况下,例程知道自己的名称以进行内省。