2

我对 Scala 编程相当陌生,所以仍在寻找规范的方法来做某事。最近,我想编写一个foo只接受一组类型作为其唯一参数的函数。想想类似的东西

def foo(x: [Int, String]) = ???

但我找不到任何接近上述语法的东西(我觉得这对我来说最自然)。使用 typeAny会丢失编译端检查,并使问题更容易逃逸到运行时领域。

我能想到的最好的是这样的:

sealed abstract class Base
case class TypeInt(v: Int) extends Base
case class TypeString(v: String) extends Base

implicit def toTypeInt(v: Int) = TypeInt(v)
implicit def toTypeString(v: String) = TypeString(v)

def foo(x: Base) = x match {
  case TypeInt(v) => println("Int: ", v)
  case TypeString(v) => println("String: ", v)
}

foo(1)
foo("hello")

(作为旁注,我希望能够编写implicit case class ...以避免手动创建toType*函数,但这不会编译。)

有没有更简单的方法来编写一个以类型安全的方式接受一组类型的参数的函数?

更新:事实证明,在我的具体情况下,我可以只使用方法重载。由于某种原因,在 Scala 工作表中根本不可能使用方法重载,这让我认为 Scala 根本没有重载。但我错了——在常规的 Scala 源代码中应该可以使用它。在下面的评论中提到的关于 Magnet 模式的文章中描述了重载使用的一些缺点(例如,由于 JVM 泛型中的类型擦除,无法对类型 Foo[Type1] 和 Foo[Type2] 进行重载。

4

1 回答 1

4

磁铁模式在这里感觉有点矫枉过正——你可以使用普通的旧类型类:

trait Fooable[A] { def apply(a: A): Unit }

implicit object intFooable extends Fooable[Int] {
  def apply(a: Int) = printf("Int: %d\n", a)
}

implicit object stringFooable extends Fooable[String] {
  def apply(a: String) = printf("String: %s\n", a)
}

def foo[A: Fooable](a: A) = implicitly[Fooable[A]].apply(a)

接着:

scala> foo(1)
Int: 1

scala> foo("hello")
String: hello

假设您担心擦除后的碰撞。让我们尝试一些泛型类型的实例:

trait Bar[A]

implicit object barIntFooable extends Fooable[Bar[Int]] {
  def apply(a: Bar[Int]) = println("A bar of ints.")
}

implicit object barStringFooable extends Fooable[Bar[String]] {
  def apply(a: Bar[String]) = println("A bar of strings.")
}

然后再次:

scala> foo(new Bar[Int] {})
A bar of ints.

scala> foo(new Bar[String] {})
A bar of strings.

一切都按预期工作。

于 2013-08-18T12:25:39.090 回答