简体   繁体   English

确保 arguments 到泛型方法在特征方法中具有相同的类型

[英]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;但是,我真的很想确保arg1arg2始终具有相同的类型; that is, they should both be either Bar or Baz , and never a mix.也就是说,它们都应该是BarBaz ,而不是混合的。 My first intuition is to use generics:我的第一个直觉是使用 generics:

trait Example {
    def method[T: Foo](arg1: T, arg2: T)
}

But I run into two problems:但是我遇到了两个问题:

  1. 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?我可以在不“感染”特征的 rest 的情况下使method通用吗?
  2. I'm not actually sure my type restriction gets the result I would like.我实际上不确定我的类型限制是否会得到我想要的结果。 Can anyone confirm if my intuition is correct?谁能确认我的直觉是否正确?

Actually if you want其实如果你想

to ensure that arg1 and arg2 always have the same type;确保arg1arg2始终具有相同的类型; that is, they should both be either Bar or Baz , and never a mix也就是说,它们都应该是BarBaz ,而不是混合

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM