【问题标题】:Zeroary method with generic return type具有通用返回类型的零元方法
【发布时间】:2019-03-06 01:42:11
【问题描述】:

我有以下代码,它应该是一个工厂类。它的 apply 方法有一个泛型参数用于返回类型限制:

sealed trait Account
final case class CheckingAccount() extends Account
final case class SavingsAccount() extends Account

object Account {
    def apply[T <: Account]:T = {
        CheckingAccount()   // CheckingAccount().asInstanceOf[T]
    }
}

但如果不显式进行类型转换,编译器会报告“Banking.CheckingAccount 类型的表达式不符合执行的类型 T”。有人知道为什么吗?

【问题讨论】:

  • 如果您将方法apply 调用为Account.apply[SavingsAccount],它不会返回SavingsAccount,那么为什么要对它进行类型检查?
  • 那个函数体只是一个例子,它可能会返回任何子类型给 Account。
  • 如果它可能返回Account 的任何子类型,那么返回类型应该是Account。这不是您的函数签名在此示例中所说明的内容。
  • 很多事情都是可能的。但是,如果您承诺准确返回您被要求的T,则当您被要求提供SavingsAccount 时,您不能返回CheckingAccount。因此,您的方法不会进行类型检查。而且,很容易看出签名为def apply[T &lt;: Account]: T的方法必须总是抛出异常,因为Nothing &lt;: Account,而你保证Account.apply[Nothing]会返回一个Nothing,这是不可能的(除非您通过抛出异常或错误来保证您的方法永远不会返回)。
  • 这可能是 X-Y 问题。你为什么要客户命名别的东西?用例是什么?客户如何告诉方法它想要什么? (该方法当然必须返回其类型签名所说的返回值,毕竟它是一种类型安全的语言)

标签: scala generics types casting


【解决方案1】:

方法签名

def apply[T <: Account]: T 

保证对于每个T,它是Account 的子类型,您可以生成T

特别是,

Account.apply[Nothing]

应该“返回”Nothing 的一个实例。由于没有Nothing 的实例,因此实现这种方法的唯一方法是抛出错误/异常。换句话说,你方法的签名要求太少而承诺太多,以至于该方法实际上变得无法实现。


解决方法 1

删除类型参数。返回Account


解决方法 2

如果您想保留通用返回类型,您可能想尝试这样的方法:

sealed trait Account
final case class CheckingAccount() extends Account
final case class SavingsAccount() extends Account

trait Default[X] {
  def createDefault: X
}

implicit object DefaultCheckingAccount extends Default[CheckingAccount] {
  def createDefault = CheckingAccount()
}

implicit object DefaultSavingsAccount extends Default[SavingsAccount] {
  def createDefault = SavingsAccount()
}

object Account {
    def apply[T <: Account](implicit d: Default[T]): T = d.createDefault
}

Account[SavingsAccount]
Account[CheckingAccount]

它可以编译,但看起来有些多余(调用 Account[SavingsAccount] 而不仅仅是 SavingsAccount() 有什么意义?)

【讨论】:

  • 你的回答有点像假设我在问 X。但仍然很好!我喜欢这个讨论!谢谢!
猜你喜欢
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
相关资源
最近更新 更多