【问题标题】:Scala: return different type depending on parameter - withouth castingScala:根据参数返回不同的类型-无需强制转换
【发布时间】:2015-03-29 14:53:12
【问题描述】:

我正在尝试编写一个函数,它可以根据传入的参数返回不同的类型。举一个非常简单的例子,这是我想要达到的理想情况: 给定这样的对象:

case object NameToken
case object SalaryToken
case object IsDirectorToken

val john: Employee

然后:

  • john.get(NameToken) 将返回“John”(字符串),
  • john.get(SalaryToken) 将返回 50000(一个 Int),
  • john.get(IsDirectorToken) 将返回 false(布尔值)。

以下是我想到的几个可能的实现。不用说,两者都很可怕。

可能的实现1:

trait Token[A]
case object NameToken extends Token[String]
case object SalaryToken extends Token[Int]
case object IsDirectorToken extends Token[Boolean]

case class Employee(name: String, salary: Int, isDirector: Boolean) {
  def get[A](t: Token[A]): A = t match {
    case NameToken => name.asInstanceOf[A]
    case SalaryToken => salary.asInstanceOf[A]
    case IsDirectorToken => isDirector.asInstanceOf[A]
  }
}

可能的实现方式 2:

trait Token2 {
  type returnType
}
case object NameToken2 extends Token2 {
  type returnType = String
}
case object SalaryToken2 extends Token2 {
  type returnType = Int
}
case object IsDirectorToken2 extends Token2  {
  type returnType = Boolean
}

case class Employee2(name: String, salary: Int, isDirector: Boolean) {
  def get(t: Token2): t.returnType = t match {
    case NameToken2 => name.asInstanceOf[t.returnType]
    case SalaryToken2 => salary.asInstanceOf[t.returnType]
    case IsDirectorToken2 => isDirector.asInstanceOf[t.returnType]
  }
}

然而,他们俩的演员阵容都很糟糕。

我可以更聪明地解决这个问题吗?

谢谢。

【问题讨论】:

  • 这是一个问题。为什么?
  • 那么,在编译的时候,编译器没有办法知道这个函数返回什么类型?所以它必须假设 Any(Int. Boolean, String 的常见超类型),所以你必须再次转换它才能将它用作 Int、Boolean 或 String。因此,您需要知道它必须使用什么(运行时)类型才能安全地执行此操作。所以,是的 - 为什么?
  • 解释一下我是如何进入这个角落的。这种方法实际上在域的上下文中是有意义的(它与员工无关),但我现在很满意它无法做到。
  • 以下两个答案似乎符合您的要求,请您看一下。
  • 可以通过宏或依赖类型(我的意思是无形的)进行更通用的求解,现在没有时间发布它,稍后会尝试。

标签: scala


【解决方案1】:
class Employee(val name: String, val salary: Int, val isDirector: Boolean) {
  def get[T](t: Token[T]): T = t.value(this)
}

trait Token[T] { def value(e: Employee): T }
object NameToken extends Token[String] { def value(e: Employee) = e.name }
object SalaryToken extends Token[Int] { def value(e: Employee) = e.salary }
object IsDirectorToken extends Token[Boolean] { def value(e: Employee) = e.isDirector }

用法

scala> val john = new Employee("John", 50000, false)
john: Employee = Employee@59f99ea

scala> val name = john.get(NameToken)
name: String = John

scala> val salary = john.get(SalaryToken)
salary: Int = 50000

scala> val isDirector = john.get(IsDirectorToken)
isDirector: Boolean = false

【讨论】:

  • 我宁愿保留在 Employee 类中提取值的逻辑,但这是我没有想到的解决方案,我正在重新考虑整个方法,但我已经接受了你的回答,因为它仍然很有趣。
【解决方案2】:

你可以使用重载:

  case class Employee(name: String, salary: Int, isDirector: Boolean) {
  def get(t: Token[String]) = name;
  def get(t: Token[Int]) = salary;
  def get(t: Token[Boolean]) = isDirector;
  }    

【讨论】:

  • 你的意思是超载。
  • 你说得对,我在答案中更改了谢谢 Thomas
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2018-04-24
  • 1970-01-01
  • 2023-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多