如何将特征声明为采用隐式“构造函数参数”?
我正在设计一个类层次结构,它由一个基类和几个特征组成。基类提供了几种方法的默认实现,特征通过抽象覆盖选择性地覆盖某些方法,从而充当可堆叠的特征/混合。
从设计角度来看,这效果很好,并且映射到域,以便我可以从这里添加过滤函数(一个特征),并使用这里的谓词(另一个特征)等。
但是,现在我希望我的一些特征采取隐式参数。我很高兴这从设计角度来看仍然有意义,并且在实践中不会造成混乱。但是,我无法说服编译器使用它运行。
问题的核心似乎是我无法为特征提供构造函数参数,以便它们可以被标记为隐式。在方法实现中引用隐式参数无法编译,并出现预期的“无法找到隐式值”消息;我试图将隐式从构造阶段(实际上,它始终在范围内)“传播”到方法中可用,但是
implicit val e = implicitly[ClassName]
(毫无疑问,正如你们中的许多人所期望的那样)该定义失败了同一条消息。
看来这里的问题是我无法说服编译器使用隐式 ClassName 标志来标记特征本身的签名,并强制调用者(即那些将特征混合到对象中的人)提供隐含的。目前,我的调用者正在这样做,但编译器并未在此级别进行检查。
是否有任何方法可以将特征标记为要求在构造时提供某些隐式?
(如果没有,这是否还没有实现,或者是否有更深层次的原因导致这是不切实际的?)
I'm designing a class hierarchy, which consists of a base class along with several traits. The base class provides default implementations of several methods, and the traits selectively override certain methods via abstract override
, so as to acts as stackable traits/mixins.
From a design perspective this works well, and maps to the domain so that I can add a filtering function from here (one trait) with a predicate from here (another trait) etc.
However, now I'd like some of my traits to take implicit parameters. I'm happy that this still makes sense from a design perspective, and wouldn't prove confusing in practice. However, I cannot convince the compiler to run with it.
The core of the problem seems to be that I cannot provide constructor arguments for a trait, such that they could be marked implicit. Referencing the implicit parameter within a method implementation fails to compile with the expected "could not find implicit value" message; I tried to "propagate" the implicit from construction stage (where, in practice, it's always in scope) to being available within the method via
implicit val e = implicitly[ClassName]
but (as no doubt many of you expect) that definition failed with the same message.
It seems that the problem here is that I can't convince the compiler to tag the signature of the trait itself with an implicit ClassName
flag, and force callers (i.e. those who mix the trait into an object) to provide the implicit. Currently my callers are doing so, but the compiler isn't checking at this level.
Is there any way to mark a trait as requiring certain implicits be available at construction time?
(And if not, is this simply not implemented yet or is there a deeper reason why this is impractical?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是不可能的。
但是您可以
隐式
和 Scala 的类型推断来使其尽可能轻松。然后
简洁,甚至不需要在扩展类中编写类型。
This isn't possible.
But you can use
implicitly
and Scala's type inference to make this as painless as possible.and then
Succinct, and doesn't even require writing the type in the extending class.
其实我以前也经常有这样的想法,但只是想出了这个主意。您可以翻译
为[编辑:原始版本没有提供对其他方法的隐式访问]
Actually, I've wanted this quite often before, but just came up with this idea. You can translate
to [EDITED: original version didn't provide access to implicit for other methods]
我遇到过这个问题几次,确实有点烦人,但还不算太烦人。抽象成员和参数通常是做同一件事的两种替代方法,各有优缺点。对于具有抽象成员的特征来说并不太不方便,因为你仍然需要另一个类来实现该特征。*
因此,你应该在特征中简单地有一个抽象值声明,以便实现类必须为你提供一个隐式的。请参阅以下示例 - 它可以正确编译,并显示了实现给定特征的两种方法:
我展示的基本想法也出现在 Knut Arne Vedaa 的答案中,但我试图制作一个更引人注目和更方便的示例,放弃使用不需要的功能。
I ran into this problem a few times and indeed it's a bit annoying, but not too much. Abstract members and parameters are usually two alternative ways of doing the same thing, with their advantages and disadvantages. For traits having an abstract member is not too inconvenient, because you still need another class to implement the trait.*
Therefore, you should simply have an abstract value declaration in the trait, so that implementing classes have to supply an implicit for you. See the following example - which compiles correctly, and shows two ways of implementing the given trait:
The basic idea I show is also present in Knut Arne Vedaa's answer, but I tried to make a more compelling and convenient example, dropping usage of unneeded features.
你可以这样做:
但我不确定其中是否有任何意义 - 你也可以显式引用隐式值。
我猜你想要的是在实例化中摆脱
i
的实现,但正如你自己所说,问题的核心是特征不接受构造函数参数 - 无论它们是隐式与否并不重要。这个问题的一个可能的解决方案是在已经有效的语法中添加一个新功能:
如果隐式在范围内,则编译器将实现 i 。
You could do it like this:
But I'm not sure if there's any point in it - you could just as well reference the implicit value explicitly.
I guess what you want is to get rid of the implementation of
i
in the instantiation, but as you say yourself, the core of the problem is that traits doesn't take constructor parameters - whether they would be implicit or not doesn't matter.A possible solution for this problem would be to add a new feature to the already valid syntax:
where
i
would be implemented by the compiler if an implicit was in scope.由于看起来这是不可能的,因此我选择在基类的构造函数上声明隐式
val
。正如问题中所指出的,这并不理想,但它满足编译器的要求,并且实际上,在我的特定情况下并没有太大的负担。如果有人有更好的解决方案,我很乐意听到并接受。
As it looks like this isn't possible, I went for the option of declaring the implicit
val
on the base class' constructor. As pointed out in the question this isn't ideal, but it satisfies the compiler and, pragmatically, isn't too much of a burden in my particular case.If anyone has a better solution though, I'd be happy to hear and accept it.