【问题标题】:Adding user mode types for Perl 6 NativeCall structs为 Perl 6 NativeCall 结构添加用户模式类型
【发布时间】:2017-05-06 14:10:35
【问题描述】:

Perl 6 docs 列出了一堆类型。其中一些,例如Str,具有更复杂的装箱/拆箱行为。

是否可以定义我自己的类型,指定我自己的装箱/拆箱例程?对于一个特定的项目,我有一堆我正在重用的类型,基本上一遍又一遍地剪切/粘贴我的访问器函数。

例如,C 结构使用time_t,我插入访问器方法来访问/来自DateTime。另一个例子是逗号分隔的列表,我想去/来自Array 并自动处理split/join

有没有更好的方法来做到这一点?

编辑:添加示例:

constant time_t = uint64;
constant FooType_t = uint16;

enum FooType <A B C>;

class Foo is repr('CStruct') is rw
{
    has uint32    $.id;
    has Str       $.name;
    has FooType_t $.type;
    has time_t    $.time;

    method name(Str $n?) {
        $!name := $n with $n;
        $!name;
    }

    method type(FooType $t?) {
        $!type = $t with $t;
        FooType($!type);
    }

    method time(DateTime $d?) {
        $!time = .Instant.to-posix[0].Int with $d;
        DateTime.new($!time)
    }
}

my $f = Foo.new;
$f.id = 12;
$f.name('myname');
$f.type(B);
$f.time(DateTime.new('2000-01-01T12:34:56Z'));

say "$f.id() $f.name() $f.type() $f.time()";

# 12 myname B 2000-01-01T12:34:56Z

这行得通,我可以用 Perl-ish 方式设置 CStruct 的各个字段(没有左值,但我可以将它们作为参数传递)。

现在我想将time_tFooType_t 等用于许多结构中的许多字段,并让它们以相同的方式运行。除了一遍又一遍地复制这些方法之外,还有更好的方法吗?

也许宏在这里可以提供帮助?我还没有掌握它们。

【问题讨论】:

  • 随着我也处理其中的一些问题,内存管理变得具有挑战性。可能最好将 CStruct 非常原始地处理并在顶部分层一个更智能的类。
  • 顺便说一句:我喜欢 NativeCall。与 C 库交互是多么容易。

标签: raku boxing nativecall


【解决方案1】:

您可以编写一个特征来处理获取或存储属性时的自动属性转换。以下内容应该可以帮助您入门:

multi sub trait_mod:<is>(Attribute:D $attr, :$autoconv!) {
    use nqp;
    my $name := $attr.name;
    $attr.package.^add_method: $name.substr(2), do given $attr.type {
        when .REPR eq 'P6int' {
            method () is rw {
                my $self := self;
                Proxy.new:
                    FETCH => method () {
                        $autoconv.out(nqp::getattr_i($self, $self.WHAT, $name));
                    },
                    STORE => method ($_) {
                        nqp::bindattr_i($self, $self.WHAT, $name,
                            nqp::decont($autoconv.in($_)));
                    }
            }
        }

        default {
            die "FIXME: no idea how to handle {.^name}";
        }
    }
}

例如,以time_t 的用例为例:

constant time_t = uint64;

class CTimeConversion {
    multi method in(Int $_ --> time_t) { $_ }
    multi method in(DateTime $_ --> time_t) { .posix }
    method out(time_t $_ --> DateTime) { DateTime.new($_) }
}

class CTimeSpan is repr<CStruct> {
    has time_t $.start is autoconv(CTimeConversion);
    has time_t $.end is autoconv(CTimeConversion);
}

最后,一些示例代码来展示它的工作原理:

my $span = CTimeSpan.new;
say $span;
say $span.end;

$span.end = DateTime.now;
say $span;
say $span.end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-22
    • 1970-01-01
    相关资源
    最近更新 更多