【问题标题】:Method generalization in ScalaScala 中的方法泛化
【发布时间】:2017-07-06 19:27:23
【问题描述】:

我试图概括一种提供类型安全 API 的方法,如下所示:

abstract class AbstractCommand {
  type T = this.type
  def shuffler(s: T => Seq[AbstractCommand])
}

class TestCommand extends AbstractCommand {
  override def shuffler(s: (TestCommand) => Seq[AbstractCommand]): Unit = ??? //error
}

我希望函数参数的预期类型在这个层次结构中是最具体的。但它没有用。

有没有办法在 Scala 中做类似的事情而不引入一些辅助类型参数?

【问题讨论】:

  • “最衍生”是指“最具体”吗?
  • @stefanobaghino 是的
  • 你可以试试F-bounded polymorphism
  • @dk14 我也这么认为,但我相信 St.Antario 想避免类型参数。
  • @stefanobaghino 作为折衷方案,您可以改用类型成员(但仍必须在派生类中手动分配它们)

标签: scala generics


【解决方案1】:

这看起来是F-Bounded Polymorphism 的完美用例:

abstract class AbstractCommand[T <: AbstractCommand[T]] {
  self: T =>
  def shuffler(s: T => Seq[AbstractCommand[T]])
}

class TestCommand extends AbstractCommand[TestCommand] {
  override def shuffler(s: (TestCommand) => Seq[AbstractCommand[TestCommand]]): Unit = ???
}

并且使用类型成员而不是类型参数(使用Attempting to model F-bounded polymorphism as a type member in Scala提供的示例):

abstract class AbstractCommand { self =>
  type T >: self.type <: AbstractCommand
}

class TestCommand extends AbstractCommand {
  type T = TestCommand
}

class OtherCommand extends AbstractCommand {
  type T = OtherCommand
}

【讨论】:

  • 同意,已经明白了。但我认为你在抽象类中忘记了self: T =&gt;
  • @St.Antario 绝对是。没有看到你们已经在另一个答案的评论中谈论过这个:X
  • 顺便说一句。你不知道是否可以使用类型成员实现 F 有界多态性?不是泛型类型。
  • 你的意思是类型成员而不是类型参数?
  • 非常感谢。明白了。
【解决方案2】:

你可以避免在抽象类中定义 T :

abstract class AbstractCommand {
  type T
  def shuffler(s: T => Seq[AbstractCommand])
}

class TestCommand extends AbstractCommand {
  type T = TestCommand
  override def shuffler(s: (TestCommand) => Seq[AbstractCommand]): Unit = ??? //compiles !
}

不利的一面是,它有点冗长,有利的一面是,它更加通用!

【讨论】:

    【解决方案3】:

    我不完全确定它是否符合您的需要,但我已经能够编译并运行以下内容,如果有帮助,请告诉我:

    abstract class AbstractCommand {
      def shuffler(s: this.type => Seq[AbstractCommand])
    }
    
    class TestCommand extends AbstractCommand {
      override def shuffler(s: (TestCommand.this.type) => Seq[AbstractCommand]): Unit = {
        s(this)
        println("success")
      }
    }
    
    new TestCommand().shuffler(_ => Seq.empty) // prints "success"
    

    【讨论】:

    • 问题是我想要唯一最具体的类型被接受
    • 据我所知,TestCommand 是最具体的类型(因为它是 AbstractCommand 的特化),并且只有该特定实现才被接受;你能给我举个例子来澄清你的评论吗?也许使用要点或类似的东西。
    • 其实是的。 F-bound多态性是一种解决方案
    • 好的,但要明确一点,这不是 F-Bounded Polymorphism,它需要一个类型参数。你可以在这里找到更多信息:twitter.github.io/scala_school/advanced-types.html#fbounded
    • @stefanobaghino 我不确定您是否知道并且根本不在答案中提及这一点,但this.type 这里比TestCommand 更具体。如果您尝试签名作者想要的 (def shuffler(s: TestCommand =&gt; Seq[AbstractCommand]): Unit),它将无法编译,除非我算错了差异。
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 2011-06-26
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多