[英]Ensure arguments to generic method have same type in trait method
I have a sealed trait and some case classes that extend that trait, like so:我有一个密封的特征和一些扩展该特征的案例类,如下所示:
sealed trait Foo
case class Bar extends Foo
case class Baz extends Foo
In a different part of my code, I have a trait with a method on it that operates on Foo
s在我的代码的不同部分,我有一个特征,其上有一个在
Foo
上运行的方法
trait Example {
def method(arg1: Foo, arg2: Foo)
}
However, I would really like to ensure that arg1
and arg2
always have the same type;但是,我真的很想确保
arg1
和arg2
始终具有相同的类型; that is, they should both be either Bar
or Baz
, and never a mix.也就是说,它们都应该是
Bar
或Baz
,而不是混合的。 My first intuition is to use generics:我的第一个直觉是使用 generics:
trait Example {
def method[T: Foo](arg1: T, arg2: T)
}
But I run into two problems:但是我遇到了两个问题:
T
needs to be present on Example
as far as I can tell.T
需要出现在Example
上。 Can I make method
generic without "infecting" the rest of the trait?method
通用吗?Actually if you want其实如果你想
to ensure that
arg1
andarg2
always have the same type;确保
arg1
和arg2
始终具有相同的类型; that is, they should both be eitherBar
orBaz
, and never a mix也就是说,它们都应该是
Bar
或Baz
,而不是混合
then然后
trait Example {
def method[T <: Foo](arg1: T, arg2: T) = ???
}
is incorrect.是不正确的。
new Example {}.method(Bar(), Baz())
compiles because T
is inferred to be Foo
. new Example {}.method(Bar(), Baz())
编译,因为T
被推断为Foo
。
Correct is正确的是
trait Example {
def method[T <: Foo, U <: Foo](arg1: T, arg2: U)(implicit ev: T =:= U) = ???
}
Then new Example {}.method(Bar(), Baz())
doesn't compile but new Example {}.method(Bar(), Bar())
and new Example {}.method(Baz(), Baz())
compile.然后
new Example {}.method(Bar(), Baz())
不会编译,但是new Example {}.method(Bar(), Bar())
和new Example {}.method(Baz(), Baz())
编译。
More details when generalized type constraints ( <:<
, =:=
and even <:!<
, =:!=
) should be preferred over type bounds ( <:
, >:
) can be found here:当广义类型约束(
<:<
, =:=
甚至<:!<
, =:!=
)应该优先于类型边界( <:
, >:
)时,可以在此处找到更多详细信息:
https://blog.bruchez.name/2015/11/generalized-type-constraints-in-scala.html (See example https://blog.bruchez.name/2015/11/generalized-type-constraints-in-scala.html (参见示例
def tupleIfSubtype[T <: U, U](t: T, u: U) = (t, u)
vs.对比
def tupleIfSubtype[T, U](t: T, u: U)(implicit ev: T <:< U) = (t, u)
there.)那里。)
https://apiumhub.com/tech-blog-barcelona/scala-generics-generalized-type-constraints/ ( https://dzone.com/articles/scala-generics-generalized-type-constraints-part-3 ) https://apiumhub.com/tech-blog-barcelona/scala-generics-generalized-type-constraints/ ( https://dzone.com/articles/scala-generics-generalized-type-constraints-part-3 )
https://herringtondarkholme.github.io/2014/09/30/scala-operator/ https://herringtondarkholme.github.io/2014/09/30/scala-operator/
You need to specify <:
您需要指定
<:
:
stands for context bound and works in combination with a type class like trait Zoo[T]
:
代表 上下文绑定,并与 class 类型结合使用,如trait Zoo[T]
<:
stands for upper type bound <:
代表类型上限
trait Example {
def method[T <: Foo](arg1: T, arg2: T)
}
Update:更新:
As @Dmytro Mitin correctly pointed out, the correct solution requires evidence check =:=
to be performed.正如@Dmytro Mitin 正确指出的那样,正确的解决方案需要执行证据检查
=:=
。
def method[T <: Foo, U <: Foo](arg1: T, arg2: U)(implicit ev: T =:= U)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.