扩展特征和类型

发布于 2024-10-04 22:46:41 字数 430 浏览 3 评论 0原文

我想要一个密封的特征,它有一个声明的方法,该方法返回 扩展特征的实际类。我应该使用抽象类型、参数类型还是 还有其他好的方法来解决这个问题吗?

sealed trait Foo {
  type T
  def doit(other: T): T
}

sealed trait Foo[T] {
  def doit(other: T): T
}

请注意,在此示例中,T 必须是 Foo 的子类型。如果我这样做的话类型 感觉信息太重复:

case class Bar(name: String) extends Foo[Bar] {
  def doit(other: Bar): Bar = ...
}

I would like to have a sealed trait which have a declared method that returns the
actual class that extends the trait. Should I use an abstract type, a parameter type or
is there any other nice way to solve this?

sealed trait Foo {
  type T
  def doit(other: T): T
}

or

sealed trait Foo[T] {
  def doit(other: T): T
}

Note that T must be a subtype of Foo in this example. If I do it like this the type
information feels too repeated:

case class Bar(name: String) extends Foo[Bar] {
  def doit(other: Bar): Bar = ...
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

囍孤女 2024-10-11 22:46:41

它们大多是可以互换的。根据 Odersky 的说法,原因主要是为了完整性:这与方法和字段(值)可以是抽象的或作为参数传递的事实类似,类型也可以。

当您打算混合使用相同类型名称的多个特征时,最好使用抽象类型。使用类型参数,您需要显式地将类型传递给每个参数,

这是一篇解释所有这些的文章: http://www.artima.com/weblogs/viewpost.jsp?thread=270195

They are mostly interchangeable. According to Odersky, the reason was mainly for completeness: That similarly to the fact that methods and fields (values) can be either abstract or passed as parameters, so can types.

It is better to use an abstract type when you intend to mix several traits that all use the same type name. With type parameters you need to explicitly pass the type to each

Here's an article explaining all of this: http://www.artima.com/weblogs/viewpost.jsp?thread=270195

岁月流歌 2024-10-11 22:46:41

您可以通过让您的 doit 方法返回工厂函数来减少重复:

trait Foo[T] { 
   self: T =>
   def doit: T => T 
}

case class Bar(name: String) extends Foo[Bar] {
   // note: types omitted 
   def doit = { other => Bar(name + other.name) }
}

不可能对抽象类型执行相同的操作:

trait Foo { 
   self: T => // won't compile because T isn't defined yet
   type T 
   def doit: T => T
}

You can cut down on the repetition somewhat by having your doit method return a factory function:

trait Foo[T] { 
   self: T =>
   def doit: T => T 
}

case class Bar(name: String) extends Foo[Bar] {
   // note: types omitted 
   def doit = { other => Bar(name + other.name) }
}

It's not possible to do the same with an abstract type:

trait Foo { 
   self: T => // won't compile because T isn't defined yet
   type T 
   def doit: T => T
}
鹿! 2024-10-11 22:46:41

您可以这样写:

trait Foo[T] {
  self:T =>
  def doit(other: T): T
}

case class Bar(name: String) extends Foo[Bar] {
  def doit(other: Bar): Bar = ...
}

与您的示例的区别在于 Bar 不能以任何其他方式实例化(例如 case class Bar(name: String) extends Foo[String])。

You can write:

trait Foo[T] {
  self:T =>
  def doit(other: T): T
}

case class Bar(name: String) extends Foo[Bar] {
  def doit(other: Bar): Bar = ...
}

The difference to your example is that Bar can't be instantiated in any other way (e.g. case class Bar(name: String) extends Foo[String]).

娇纵 2024-10-11 22:46:41
trait Foo[A <: Foo[A]]

仅当 A 是 Foo[A] 的子类型并且唯一满足该条件的类型是要混合到的类 Foo 时,才能混合此特征。我在 Lift 的 Mapper 特征中看到了这个解决方案。

trait Foo[A <: Foo[A]]

This trait can only be mixed in if A is a subtype of Foo[A] and the only type satisfying that is the class Foo is being mixed into. I saw this solution in the Mapper traits in Lift.

抽个烟儿 2024-10-11 22:46:41

编辑 - 以下是我原来的答案。您的评论表明您希望返回匹配类型的任意实例,但我真的不认为这是明智的。 假设是,通过 T.type 语法

trait T { def foo : T.type }

trait U extends T { def foo = new U } //must be a U

class W extends U

val w : W = (new W).foo //oh dear.

这可以通过 this.type 完成:

scala> trait T {
 | def foo : this.type
 | }
defined trait T

scala> class W extends T {
 | def foo  = this
 | }
defined class W

scala> (new W).foo
res0: W = W@22652552

scala> res0.foo
res1: res0.type = W@22652552

然后还有:

scala> ((new W) : T)
res4: T = W@45ea414e

scala> res4.foo.foo.foo
res5: res4.type = W@45ea414e

EDIT - Below is my original answer. Your comment indicates that you wish to return an arbitrary instance of a matching type but I don't really believe that this is in any way sensible. Suppose it were, via the T.type syntax:

trait T { def foo : T.type }

trait U extends T { def foo = new U } //must be a U

class W extends U

val w : W = (new W).foo //oh dear.

This is accomplishable via this.type:

scala> trait T {
 | def foo : this.type
 | }
defined trait T

scala> class W extends T {
 | def foo  = this
 | }
defined class W

scala> (new W).foo
res0: W = W@22652552

scala> res0.foo
res1: res0.type = W@22652552

And then also:

scala> ((new W) : T)
res4: T = W@45ea414e

scala> res4.foo.foo.foo
res5: res4.type = W@45ea414e
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文