Scala,通用元组

Gig*_*tsu 12 generics scala

我有一个可以接受任何大小的任何元组的泛型方法,唯一的限制是这个元组的第一个元素应该是类型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.


mkU*_*tra 5

这有点不安全,但在这种情况下您可以使用结构类型:

trait MyTrait {
  def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
Run Code Online (Sandbox Code Playgroud)

  • 这是[复合类型](https://www.scala-lang.org/files/archive/spec/2.12/03-types.html#compound-types)或“结构类型”,与“鸭子类型”不同,有明确定义的含义就是Scala。 (2认同)