如何制作一个继承与 IO::Path 相同方法的类?

Ste*_*ieD 5 raku

我想用 Raku 建立一个课程。这是我到目前为止所拥有的:

unit class Vimwiki::File;

has Str:D $.path is required where *.IO.e;

method size {
    return $.file.IO.s;
}
Run Code Online (Sandbox Code Playgroud)

我想size通过简单地让我的类继承 IO::Path 的方法来摆脱该方法,但我对如何实现这一点有点不知所措。is IO::Path当我尝试创建新对象时尝试抛出错误:

$vwf = Vimwiki::File.new(path => 't/test_file.md');

Must specify a non-empty string as a path
  in block <unit> at t/01-basic.rakutest line 24
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 5

Must specify a non-empty string as a path

当我看某人的SO时,我总是尝试一个人的代码。你的没用。(没有声明$vwf。)这立即提醒我有人没有应用最小可重现示例原则。

于是我就这么做了,不到 60 秒后:

IO::Path.new
Run Code Online (Sandbox Code Playgroud)

产生相同的错误。

为什么?

文档IO::Path.new显示了其签名:

multi method new(Str:D $path, ...

因此,IO::Pathnew方法需要一个位置参数,即Str. 您(和我的 MRE)尚未传递Str. 因此出现错误消息。

当然,您已经声明了自己的attribute $path,并传递了一个命名参数来设置它,不幸的是,由于与名称的重合path,这让您感到困惑,但这就是编程的乐趣。

接下来,采取#1

我认为拥有重复的路径属性IO::Path可能会导致不必要的复杂性和/或错误。所以我想我会拒绝这个。

如果您想做的只是在文件名周围进行额外的检查,那么您可以编写:

unit class Vimwiki::File is IO::Path;

method new ($path, |) { $path.IO.e ?? (callsame) !! die 'nope' }
Run Code Online (Sandbox Code Playgroud)

callsame 使用完全相同的参数将正在进行的例程调用(方法调用)重新分派给下一个最合适的候选者,如果包含未调用的new新函数,则将选择该候选者。callsame在这种情况下,下一个候选者将是 的现有new方法IO::Path

这似乎很好开始。然后您可以添加其他您认为合适的属性和方法......

接下来,采取#2

...除了您提交的错误IO::Path这意味着您无法以正常方式初始化属性,因为IO::Path违反了标准对象构造协议!:(

Liz 展示了解决此错误的一种方法。

在这个答案的早期版本中,我不仅展示而且推荐了另一种方法,即通过委托handles而不是普通继承。此后我得出的结论是,这让事情变得过于复杂,因此将其从这个答案中删除了。然后我读了你的问题!

所以我想委托方法可能仍然适合作为 bug 的解决方法。因此,如果后来的读者想看到它的实际效果,请点击 @sdondley 的链接到他们的代码。但我将其从这个答案的这个(希望是最终的!著名的遗言......)版本中删除,希望当您(后来的读者)阅读本文时,您只需要做一些非常简单的事情,例如采取# 1 .