如何定义类型参数不能为 Any 的 Scala 方法
How to define a scala method with type param that cannot be Any
在下面的示例中,我想定义一个 contains
方法,如果 a
和 b
的基类型不同,该方法将无法编译。
- 在
contains1
impl中,如果a
为Seq[Int]
且b为String
,则T
导出为Any
,并且它编译。这不是我想要的。
- 在
contains2
impl 中,如果a
是Seq[Int]
并且b 是String
,那么它不会编译。行为就是我想要的。
def contains1[T](a: Seq[T], b: T): Boolean = a.contains(b)
println(contains1(Seq(1,2,3), "four")) // false
def contains2[T: Ordering](a: Seq[T], b: T): Boolean = a.contains(b)
println(contains2(Seq(1,2,3), "four")) // compilation error
// cmd7.sc:1: No implicit Ordering defined for Any.
// val res7 = isMatched(Seq(1,2,3), "s")
^
// Compilation Failed
但是,是否有更简单的方法来实现与 contains2
中相同的行为? Ordering
上下文绑定让我感到困惑,因为该方法与 sorting/ordering 完全无关。
您可以使用广义类型约束运算符=:=
。
例如:
def contains[A,B](a: Seq[A], b: B)(implicit evidence: A =:= B): Boolean = a.contains(b)
然后:
println(contains1(Seq(1,2,3), "four")) //fails with Cannot prove that Int =:= String.
println(contains1(Seq("one"), "four")) //returns false
println(contains1(Seq("one", "four"), "four")) //true
关于广义类型约束的更多信息here and here。
正如 LuisMiguelMejíaSuárez 所注意到的,您还可以考虑使用 B <:< A
而不是 A =:= B
。我不会详细说明这两者之间的差异,因为它在链接的答案和文章中有所描述,但简而言之,<:<
也将允许属于 A
的所有 B
,而 =:=
需要类型完全匹配。
在下面的示例中,我想定义一个 contains
方法,如果 a
和 b
的基类型不同,该方法将无法编译。
- 在
contains1
impl中,如果a
为Seq[Int]
且b为String
,则T
导出为Any
,并且它编译。这不是我想要的。 - 在
contains2
impl 中,如果a
是Seq[Int]
并且b 是String
,那么它不会编译。行为就是我想要的。
def contains1[T](a: Seq[T], b: T): Boolean = a.contains(b)
println(contains1(Seq(1,2,3), "four")) // false
def contains2[T: Ordering](a: Seq[T], b: T): Boolean = a.contains(b)
println(contains2(Seq(1,2,3), "four")) // compilation error
// cmd7.sc:1: No implicit Ordering defined for Any.
// val res7 = isMatched(Seq(1,2,3), "s")
^
// Compilation Failed
但是,是否有更简单的方法来实现与 contains2
中相同的行为? Ordering
上下文绑定让我感到困惑,因为该方法与 sorting/ordering 完全无关。
您可以使用广义类型约束运算符=:=
。
例如:
def contains[A,B](a: Seq[A], b: B)(implicit evidence: A =:= B): Boolean = a.contains(b)
然后:
println(contains1(Seq(1,2,3), "four")) //fails with Cannot prove that Int =:= String.
println(contains1(Seq("one"), "four")) //returns false
println(contains1(Seq("one", "four"), "four")) //true
关于广义类型约束的更多信息here and here。
正如 LuisMiguelMejíaSuárez 所注意到的,您还可以考虑使用 B <:< A
而不是 A =:= B
。我不会详细说明这两者之间的差异,因为它在链接的答案和文章中有所描述,但简而言之,<:<
也将允许属于 A
的所有 B
,而 =:=
需要类型完全匹配。