我有一个通用方法,可以接受任何大小的任何元组,唯一的约束是该元组的第一个元素应为MyClass
类型。
类似这样的东西:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
我已经尝试过了
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
但出现错误unboud wildcard type
答案 0 :(得分:11)
如果您想在没有样板或运行时反射的情况下执行此操作,那么Shapeless是您的最佳选择。您可以使用audioCtx= track.createMediaElementSource(audioElement);
类型类将类型级别的约束放在元组的第一个元素上:
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)
}
如果需要使用特征,可以将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)
^
(用于“证据”)要求放在定义中而不是在构造函数中:
ev
现在,任何实例化trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
的类都必须提供证据,证明MyTrait
是一个以P
作为第一个元素的元组。
答案 1 :(得分:4)
这有点不安全,但是在这种情况下,您可以使用“结构类型”:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
答案 2 :(得分:2)
Scala无法使用大小未知的通用元组,因为Products不继承主题本身。您可以尝试通过play json lib使用Shapeless或Products。
答案 3 :(得分:0)
您需要从Product
继承特征,通过它您可以让productIterator
,productArity
和productElement
处理返回的值。这是一个例子
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
您可以像这样调用
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
希望这对您有所帮助。
答案 4 :(得分:-1)
正如其他人所说,您可以使用无定形:
import shapeless.ops.tuple.IsComposite
import shapeless.syntax.std.tuple._
class MyClass(i : Int){
def hello() = println(i)
}
object Tup extends App {
def getMyClass[P <: Product](p: P)(implicit ev: IsComposite[P]): MyClass = {
if (p.head.isInstanceOf[MyClass]) p.head.asInstanceOf[MyClass] else throw new Exception()
}
val x= (new MyClass(1),5,6)
val y = (new MyClass(2),7)
val c = getMyClass(x)
val c1 = getMyClass(y)
c.hello()
c1.hello()
val c2 = getMyClass((1,5,6,7)) // exception
c2.hello()
}
答案 5 :(得分:-1)
如果您正在寻找编译时间保证,那么这是以下情况的用例之一 无形,
您需要在build.sbt
中添加Shapeless,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
现在,您可以使用Shapeless来定义带有编译时间保证的类型安全getter,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
现在,如果您要使用特定类型的“第一个”吸气剂来丰富元组,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
如果您不需要隐式扩充,而只是在寻找一种将类型“锁定”在吸气剂中并将其用于相应类型的方法,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)