役割グループのモジュールをどのように作成できますか?


8

ロールの機能はロールグループです。これにより、マルチルーチンと同様に、異なるパラメーターを受け入れる同じ名前で複数のロールを宣言できます。

role Foo[Int:D] {
    method is-int(::?CLASS:_: --> True)  { }
    method is-str(::?CLASS:_: --> False) { }
}
role Foo[Str:D] {
    method is-int(::?CLASS:_: --> False) { }
    method is-str(::?CLASS:_: --> True)  { }
}

多くの場合、1つのタイプに対して、1つのモジュールがあります。問題はunit、モジュール内でスコープ宣言を1つしか持てないため、役割グループで使用できないことです。役割グループのモジュールをどのように作成できますか?

回答:


9

unitスコープ宣言のないモジュールを作成してそこからシンボルをエクスポートできますが、役割グループをエクスポートする方法には少し問題があります。is export間違ったタイプをエクスポートするため、この特性を使用することはできません。宣言された後で役割を参照する場合、その中の個々の役割ではなく役割グループを参照しますが、個々の役割で使用is exportすると、役割のグループではなく、それらの個々の役割がエクスポートされます。個々の役割は役割グループとは非常に異なる方法であり、通常の役割が期待するようには動作しません。

幸い、EXPORTパッケージを使用してこれを行う方法があります。Fooこのパッケージで役割グループを宣言すると、に不要な名前が付けEXPORT::DEFAULT::FooられるためMY、ユニットのスコープで宣言し、EXPORT::DEFAULT代わりに定数を宣言する必要があります。

use v6.d;

my role Foo[Int:D] {
    method is-int(::?CLASS:_: --> True)  { }
    method is-str(::?CLASS:_: --> False) { }
}
my role Foo[Str:D] {
    method is-int(::?CLASS:_: --> False) { }
    method is-str(::?CLASS:_: --> True)  { }
}

my package EXPORT::DEFAULT {
    constant Foo = ::Foo;
}

これFooでインポートして使用できます。

use Foo;

say ::<Foo>:exists;       # OUTPUT: True
say try Foo[1].is-int;    # OUTPUT: True
say try Foo['ok'].is-str; # OUTPUT: True

注:::定数名では使用できないため、名前空間で役割グループをエクスポートするには、それを別のパッケージでラップする必要があります。

my role Foo::Bar[Int:D] { }
my role Foo::Bar[Str:D] { }

my package EXPORT::DEFAULT {
    package Foo {
        constant Bar = Foo::Bar;
    }
}

3

単純です。our周囲をunit何もせずにデフォルトのスコープを使用します。

unit唯一あなたが持つファイル全体を包囲する必要がないように添加し、{そして}一つだけがあったときmodulepackageclassrole、またはsubファイルに。
常に使用する必要はありません。
実際、それを使用する必要はありません。


必要に応じて、パラメータ化せずに前方宣言を追加します。
それに追加された特性は、通常、同じ名前のすべての役割に適用されます。

lib/Foo/Bar.rakumod

use v6.d;

role Foo::Bar {…} # is export would be added here

role Foo::Bar[Int:D] {
    method is-int(::?CLASS:_: --> True)  { }
    method is-str(::?CLASS:_: --> False) { }
}
role Foo::Bar[Str:D] {
    method is-int(::?CLASS:_: --> False) { }
    method is-str(::?CLASS:_: --> True)  { }
}

その後、それを使用すると、完全修飾名でアクセスできるように自動的にロードされます。

{
    use lib <lib>; # only needed because it is not installed

    use Foo::Bar;

    say Foo::Bar[ 1].is-int; # True
    say Foo::Bar[''].is-str; # True

    say Foo::Bar.^name; # Foo::Bar
}

say Foo::Bar.^name; # error: Could not find symbol 'Bar' in 'Foo'

この場合、それをモジュールステートメントの中に置くことができるので、Foo::それほど頻繁に書く必要はありません。

lib/Foo/Bar.rakumod

use v6.d;

unit module Foo;

role Bar {…}

role Bar[Int:D] {
    method is-int(::?CLASS:_: --> True)  { }
    method is-str(::?CLASS:_: --> False) { }
}
role Bar[Str:D] {
    method is-int(::?CLASS:_: --> False) { }
    method is-str(::?CLASS:_: --> True)  { }
}

役割は引き続きとしてアクセスできますFoo::Bar
これが前の例とまったく同じコードになったとしても、私は驚かないでしょう。

追加する唯一の理由is exportは、のBar代わりにとしてエクスポートしたい場合ですFoo::Bar。これは、上記の例の両方に当てはまります。


いつも使う必要があると思っていたのではないでしょうかis export。多くの場合、そうではありません。

unit module Foo::Bar; # default `our` scoped

our sub baz ( --> 'hello world'){}
use Foo::Bar;

say Foo::Bar::baz(); # hello world
# this works because it was declared as `our`

baz()モジュールのスコープ内で使用したいだけの場合は、それをエクスポートする必要があります。

unit module Foo::Bar;

our sub baz ( --> 'hello world') is export {}
use Foo::Bar;
say Foo::Bar::baz(); # hello world

# available because of `is export`
say baz(); # hello world

私がまだそれを宣言したことに注意してください。our誰かがあなたにそれをエクスポートしてほしくない場合でも、それらはまだアクセス可能です。

use Foo::Bar ();

# say baz(); # baz used at line 1. Did you mean 'bag'?

say Foo::Bar::baz(); # hello world

の全体的な目的はis export、関数に完全修飾名を使用する必要をなくすことです。役割などにも機能することは副次的な利点です。


ああ、私はour-scoped宣言のないモジュールのunit-scoped宣言が何らかの理由でグローバルになると思っていました。私is exportはそれが人々が最初にこのような何かをエクスポートしようとするかもしれない方法であると思ったので、私は行動を述べました。
Kaiepi

私はそうunit module Fooすべきだと思いunit package Fooます。それはモジュールの場合は、既存のがあるかどうFoo他の場所では、そのシンボルは、両方の場合は、正しくマージしませんFoo::Barし、Fooインポートされます。
Kaiepi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.