Làm thế nào bạn có thể viết một mô-đun cho một nhóm vai trò?


8

Một tính năng của vai trò là các nhóm vai trò, cho phép bạn khai báo nhiều vai trò có cùng tên chấp nhận các tham số khác nhau, tương tự như nhiều thói quen:

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)  { }
}

Thông thường, đối với một loại, bạn có một mô-đun. Vấn đề là bạn chỉ có thể có một unitkhai báo có phạm vi trong một mô-đun, vì vậy bạn không thể sử dụng nó với các nhóm vai trò. Làm thế nào bạn có thể viết một mô-đun cho một nhóm vai trò?

Câu trả lời:


9

Bạn có thể có các mô-đun mà không cần unit khai báo trong phạm vi và xuất các ký hiệu từ nó, nhưng cách bạn xuất một nhóm vai trò là một vấn đề. Bạn không thể sử dụng is exportđặc điểm này, vì điều đó sẽ xuất các loại sai. Khi bạn đề cập đến một vai trò sau khi đã được tuyên bố, bạn đang đề cập đến nhóm vai trò, không phải các vai trò riêng lẻ trong vai trò đó, nhưng sử dụng is exporttrên các vai trò riêng lẻ sẽ xuất các vai trò riêng lẻ đó, không phải nhóm vai trò đó. Vai trò cá nhân có CÁCH rất khác với các nhóm vai trò và sẽ không hành xử như bạn thường mong đợi vai trò!

May mắn thay, có một cách để làm điều này bằng cách sử dụng EXPORTgói. Khai báo Foonhóm vai trò trong gói này sẽ đặt tên cho nó EXPORT::DEFAULT::Foo, cái mà bạn có thể không muốn, vì vậy bạn sẽ muốn khai báo nó trong MYphạm vi của đơn vị và khai báo một hằng số cho nó trongEXPORT::DEFAULT thay vào đó :

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;
}

Bây giờ Foocó thể được nhập và sử dụng OK:

use Foo;

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

Lưu ý: bạn không thể sử dụng ::tên không đổi, vì vậy, để xuất một nhóm vai trò trong không gian tên, bạn sẽ cần phải bọc nó trong một gói khác:

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

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

3

Đơn giản, chỉ cần sử dụng ourphạm vi mặc định mà không có xung quanhunit bất cứ điều gì .

unitchỉ bổ sung để bạn sẽ không phải xung quanh một tập tin toàn với {}khi có chỉ có một module, package, class, role, hoặc subtrong file.
Bạn không phải luôn luôn sử dụng nó.
Trong thực tế, bạn không bao giờ phải sử dụng nó.


Nếu bạn muốn, thêm một khai báo chuyển tiếp mà không cần tham số hóa.
Một đặc điểm được thêm vào nó thường sẽ áp dụng cho tất cả các vai trò có cùng tên.

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)  { }
}

Sau đó, khi bạn sử dụng nó, nó sẽ tự động được tải theo cách mà nó có thể truy cập bằng tên đủ điều kiện.

{
    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'

Trong trường hợp này, bạn có thể đặt nó bên trong một câu lệnh mô-đun để bạn không cần phải viết Foo::thường xuyên như vậy.

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)  { }
}

Vai trò vẫn có thể truy cập như Foo::Bar.
Tôi sẽ không ngạc nhiên nếu điều này dẫn đến mã chính xác như ví dụ trước.

Lý do duy nhất để thêm is exportlà nếu bạn muốn nó được xuất ra Barthay vì Foo::Bar. Điều này áp dụng cho cả hai ví dụ trên.


Tôi đoán là bạn nghĩ rằng bạn luôn luôn cần phải sử dụng is export. Trong nhiều trường hợp bạn thực sự không.

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`

Nếu bạn muốn có thể chỉ sử dụng baz()trong khi có nó bên trong phạm vi của mô-đun, thì và chỉ sau đó bạn mới cần xuất nó.

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

Lưu ý rằng tôi vẫn tuyên bố như ourvậy nếu ai đó không muốn bạn xuất nó, họ vẫn có thể truy cập được.

use Foo::Bar ();

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

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

Toàn bộ mục đích is exportlà để loại bỏ nhu cầu sử dụng tên đủ điều kiện cho các chức năng. Rằng nó cũng hoạt động cho những thứ như vai trò là một lợi ích phụ.


Ah, tôi nghĩ rằng các ourkhai báo có phạm vi trong các mô-đun mà không có các unitkhai báo có phạm vi đã trở thành toàn cầu vì một số lý do. Tôi đã đề cập đến hành vi này is exportbởi vì tôi cho rằng đó là cách đầu tiên mọi người có thể cố gắng xuất một cái gì đó như thế này.
Kaiepi

Tôi nghĩ rằng unit module Foonên được unit package Foomặc dù. Nếu đó là một mô-đun, thì nếu có bất kỳ Foonơi nào tồn tại ở nơi khác, thì các biểu tượng sẽ không hợp nhất nếu cả hai Foo::BarFoođược nhập.
Kaiepi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.