我有一个可以接受任何大小的任何元组的泛型方法,唯一的限制是这个元组的第一个元素应该是类型MyClass.
像这样的东西:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
Run Code Online (Sandbox Code Playgroud)
我试过这个
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
Run Code Online (Sandbox Code Playgroud)
但我得到了错误 unboud wildcard type
Tra*_*own 11
如果你想在没有样板或运行时反射的情况下做到这一点,那么Shapeless是你最好的选择.您可以使用IsComposite类型类将类型级约束放在元组的第一个元素上:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
Run Code Online (Sandbox Code Playgroud)
然后:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
Run Code Online (Sandbox Code Playgroud)
如果需要使用特征,可以将ev(for"evidence")要求放在定义中而不是构造函数中:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Run Code Online (Sandbox Code Playgroud)
现在任何类实例化MyTrait都必须提供作为第一个元素P的元组的证据MustBeFirst.
这有点不安全,但在这种情况下您可以使用结构类型:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1038 次 |
| 最近记录: |