如何定义可以是该类型的类型或容器的类型参数?

时间:2018-03-15 15:33:55

标签: scala generics containers

我想定义一个这样的类:

class MyClass[C,X](
  val states: C,
  val transform: C => X
)

X只能等于CC的容器,例如List[C]Set[C] - 它对于如果将X定义为其他任何内容,则会出现问题。

有没有办法在Scala中强加这个限制?

2 个答案:

答案 0 :(得分:2)

你可以尝试

import scala.language.higherKinds

class MyClass[C, F[_]](
                       val states: C,
                       val transform: C => F[C]
                      )

type Id[A] = A

new MyClass[Int, Set](1, Set(_)) // Set[Int] is a container for Int
new MyClass[String, List]("a", List(_)) // List[String] is a container for String
new MyClass[Boolean, Id](true, x => x) // Id[Boolean] is Boolean itself

答案 1 :(得分:1)

修改

假设XY问题。现在这个帖子有两个答案:

  1. 依赖于子类化的繁琐解决方案
  2. 基于类的基于类的解决方案,可能解决实际的X
  3. <强>子类的溶液

    如果你跑

    List(List(0), Set(0))
    
    解释器中的

    ,您会看到ListSet仅在Iterable统一。

    因此,您可以做出的最具体的限制是:

    import scala.language.higherKinds
    
    class MyClass[C, Container[X] <: collection.immutable.Iterable[X]] (
      val states: C,
      val transform: C => Container[C]
    )
    

    我不建议让它这个通用。如果有疑问,请先取List,只有在实际必要时才进行概括。

    <强>类型类的溶液

    从你的评论中看,它看起来好像是一个XY问题,你真正想要的是一个具有适当类型类的类型构造函数F

    首先定义你的类型类,例如使用一个sholud能够遍历F的约束:

    trait MyTC[F[_]] {
      def hasIterator[X](fx: F[X]): Iterator[X]
    }
    

    然后为具有类型类实例的任意MyClass定义F

    class MyClass[X, F[_] : MyTC] {
      val states: X
      val transform: X => F[X]
    }
    

    然后只需为MyTCListSet定义Id的实例:

    implicit object ListMyTC extends MyTC[List] {
      def hasIterator[X](lx: List[X]): Iterator[X] = lx.iterator
    }
    
    type Id[X] = X
    implicit object ListMyTC extends MyTC[Id] {
      def hasIterator[X](x: X): Iterator[X] = Iterator(x)
    }
    

    然后您可以将MyClassListId一起使用:

    val m1 = new MyClass[Int, List] { ... } // Integer states, transforms to List
    val m2 = new MyClass[String, Id] { ... } // String-labeled states, transforms to other `String`
    

    这个想法主要是用一个内涵定义来替换你扩展枚举你认为你的构造可能起作用的所有容器类型的尝试,它接受任何F可以证明它满足{的所有要求。 {1}}通过提供MyTC

    的实例