在 Scala 中重载泛型方法
Overloading generic methods in Scala
我是 Scala 的新手,遇到一个无法在线找到解决方案的问题。所以我在这里寻求帮助。
我想做的是在 class A
中实现两个 map
方法。这两个方法都接受一个闭包,但是对于其中一个,闭包的 return 值的类型是 Tuple2
。此外,两个 map
方法的 return 值不相同 class (这就是为什么我需要两个 'map' 方法)。代码简化如下:
object Test {
class A[T] {
def map[V](a: T => V): A[V] = {
null
}
def map[K, V](a: T => Tuple2[K, V]): B[K, V] = {
null
}
}
class B[K, V] extends A[Tuple2[K, V]] {}
def main(args: Array[String]) {
new A[Int].map(x => x + 1) //compile error
new A[Int].map{x => x + 1} //compile error
new A[Int].map{x:Int => x + 1} //passed but ugly in use
}
}
class A
和 B
以及两个 map
方法的定义在我的计算机上被 Scala 接受。问题来了。正如我在 main
方法中展示的,我如何在 class A
中使用映射方法,前两个语句导致编译错误(说在闭包中缺少 x
的参数类型) 只有最后一个是可执行的。
并且如果我删除 class A
中的第二个 map
方法,前两个语句将变得可执行。我不知道为什么以及我应该怎么做。我只想让这两个方法共享相同的名称map
,同时我不需要在使用map
方法时告诉闭包参数的类型。
希望对这个问题感兴趣的人给我一个更好的设计。提前致谢。
编译器想要确定x的类型,为此,它必须首先确定使用了两个映射函数中的哪一个。但是,除非知道参数的类型,否则它无法知道使用了哪个映射函数。因此编译器不能这样做。
在这种特定情况下,可以推断 x 的类型将是 Int
,无论选择哪个 map 函数,但是不幸的是,编译器无法确定这一点。
可能的是明确指定映射函数的类型参数。这样编译器就知道要使用哪个函数(以及什么类型的参数)
new A[Int].map[Int](x => x + 1)
new A[Int].map[Int, String]{x => (x, "1")}
另一种方法是给第二个 map
函数一个不同的名称,因为它的签名与 map
通常定义的方式不同。
我不知道如何使用方法重载来做到这一点。问题是类型推断器在这种情况下不起作用。您可以查看 magnet pattern 但您仍然需要指定完整的类型。相反,我使用了一种在 Scala 集合中使用的方法。请注意,仍然可能存在一些我不知道的极端情况。看一看:
object Example {
class A[T] {
def map[B, That](f: T => B)(implicit bf: CanBuildFrom[A[T], B, That]): That = {
val res = f(???)
bf(res)
}
}
class B[K, V] extends A[Tuple2[K, V]] {}
trait CanBuildFrom[-From, -Elem, +To] {
def apply(el: Elem) : To
}
def main(args: Array[String]) {
implicit def ev0[T,R] = new CanBuildFrom[A[T], R, A[R]] {
def apply(el : R) : A[R] = new A()
}
implicit def ev1[T,K,V] = new CanBuildFrom[A[T], Tuple2[K,V], B[K,V]] {
def apply(el :(K,V)) : B[K,V] = new B()
}
val res1 : B[Int, Int] = new A[Int].map(x => (2,3))
val res2 : A[Int] = new A[Int].map { x => 1 }
new A[Int].map { x => 1 }
new A[Int].map(x => (2,3))
}
}
我是 Scala 的新手,遇到一个无法在线找到解决方案的问题。所以我在这里寻求帮助。
我想做的是在 class A
中实现两个 map
方法。这两个方法都接受一个闭包,但是对于其中一个,闭包的 return 值的类型是 Tuple2
。此外,两个 map
方法的 return 值不相同 class (这就是为什么我需要两个 'map' 方法)。代码简化如下:
object Test {
class A[T] {
def map[V](a: T => V): A[V] = {
null
}
def map[K, V](a: T => Tuple2[K, V]): B[K, V] = {
null
}
}
class B[K, V] extends A[Tuple2[K, V]] {}
def main(args: Array[String]) {
new A[Int].map(x => x + 1) //compile error
new A[Int].map{x => x + 1} //compile error
new A[Int].map{x:Int => x + 1} //passed but ugly in use
}
}
class A
和 B
以及两个 map
方法的定义在我的计算机上被 Scala 接受。问题来了。正如我在 main
方法中展示的,我如何在 class A
中使用映射方法,前两个语句导致编译错误(说在闭包中缺少 x
的参数类型) 只有最后一个是可执行的。
并且如果我删除 class A
中的第二个 map
方法,前两个语句将变得可执行。我不知道为什么以及我应该怎么做。我只想让这两个方法共享相同的名称map
,同时我不需要在使用map
方法时告诉闭包参数的类型。
希望对这个问题感兴趣的人给我一个更好的设计。提前致谢。
编译器想要确定x的类型,为此,它必须首先确定使用了两个映射函数中的哪一个。但是,除非知道参数的类型,否则它无法知道使用了哪个映射函数。因此编译器不能这样做。
在这种特定情况下,可以推断 x 的类型将是 Int
,无论选择哪个 map 函数,但是不幸的是,编译器无法确定这一点。
可能的是明确指定映射函数的类型参数。这样编译器就知道要使用哪个函数(以及什么类型的参数)
new A[Int].map[Int](x => x + 1)
new A[Int].map[Int, String]{x => (x, "1")}
另一种方法是给第二个 map
函数一个不同的名称,因为它的签名与 map
通常定义的方式不同。
我不知道如何使用方法重载来做到这一点。问题是类型推断器在这种情况下不起作用。您可以查看 magnet pattern 但您仍然需要指定完整的类型。相反,我使用了一种在 Scala 集合中使用的方法。请注意,仍然可能存在一些我不知道的极端情况。看一看:
object Example {
class A[T] {
def map[B, That](f: T => B)(implicit bf: CanBuildFrom[A[T], B, That]): That = {
val res = f(???)
bf(res)
}
}
class B[K, V] extends A[Tuple2[K, V]] {}
trait CanBuildFrom[-From, -Elem, +To] {
def apply(el: Elem) : To
}
def main(args: Array[String]) {
implicit def ev0[T,R] = new CanBuildFrom[A[T], R, A[R]] {
def apply(el : R) : A[R] = new A()
}
implicit def ev1[T,K,V] = new CanBuildFrom[A[T], Tuple2[K,V], B[K,V]] {
def apply(el :(K,V)) : B[K,V] = new B()
}
val res1 : B[Int, Int] = new A[Int].map(x => (2,3))
val res2 : A[Int] = new A[Int].map { x => 1 }
new A[Int].map { x => 1 }
new A[Int].map(x => (2,3))
}
}