在Scala中使用协变不可变集合



我试图创建一个适用于任何具有take, slicedrop的集合的函数。也就是说,我想创建一个在IndexedSeq[Boolean]Vector[Boolean]上工作的函数,返回相同类型的对象。这就是我在看完这篇文章后所尝试的如何在Scala中创建泛型类型的对象/单例?

并尝试使用IndexedSeqLike代替Ordering,但无济于事

trait MutateLike[+T,-Y] {
  def apply[U >: T, Y](eo: U): Y
}
case object Mutate extends MutateLike[IndexedSeq[Boolean],IndexedSeq[Boolean]]{
  def apply[U >: IndexedSeq[Boolean],IndexedSeq[Boolean]]( eo : U ): IndexedSeq[Boolean] = {
    val point = (eo.length * scala.util.Random.nextDouble).toInt
    eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
  }  
}

在尝试了许多其他事情之后。然而,它不起作用,并产生value length is not a member of type parameter U调的错误。但是U与T协变,在这种情况下是IndexedSeq,对吧?

我认为你把你的生活弄得比它需要的复杂得多。试试这个

case object Mutate{
  def apply( eo : IndexedSeq[Boolean] ): IndexedSeq[Boolean] = {
    val point = (eo.length * scala.util.Random.nextDouble).toInt
    eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
  }  
}
scala> Mutate( IndexedSeq( true, false, false, true, false, false ) )
res8: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)
scala> Mutate( Vector( true, false, false, true, false, false ) )
res9: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)

这就是直接的、老式的面向对象的多态性。Vector[Boolean]就是IndexedSeq[Boolean],所以它是可以替代的。

通过对MutateLike及其方差的声明,您可以决定MutateLike的哪些参数化可以从MutateLike的其他参数继承。但那不是你感兴趣的表达或试图做的。

(当然,根本不需要使用对象声明。您可以将mutate定义为一个简单的函数。)

也许你想要这样的东西:

import scala.util.Random
import scala.collection.generic.CanBuildFrom
import scala.collection.SeqLike
def mutate[Repr, To](xs: SeqLike[Boolean, Repr], rng: Random)(implicit ev: CanBuildFrom[Repr, Boolean, To]) = {
  val builder = ev.apply()
  val iter = xs.iterator
  var i = rng.nextInt(xs.length)
  while (i > 0) { i -= 1; builder += iter.next }
  builder += !iter.next
  while (iter.hasNext) builder += iter.next
  builder.result
}
现在

val xs = Array(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))

搜索结果

Array[Boolean] = Array(true, true, false, false, false)

val xs = Vector(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))

导致

scala.collection.immutable.Vector[Boolean] = Vector(true, true, false, false, false)

mutate方法也可以很容易地推广到处理Booleans以外的类型集合,如下所示:

def mutate[Repr, To, A](xs: SeqLike[A, Repr], f: A => A, rng: Random)(implicit ev: CanBuildFrom[Repr, A, To]) = {
  val builder = ev.apply()
  val iter = xs.iterator
  var i = rng.nextInt(xs.length)
  while (i > 0) { i -= 1; builder += iter.next }
  builder += f(iter.next)
  while (iter.hasNext) builder += iter.next
  builder.result
}
然后

Seq.iterate("I am what I am", 16){ s=> 
  mutate(s, (ch: Char) => (ch ^ 3).toChar, rng)
}.mkString("n")

搜索结果

I am what I am
J am what I am
I am what I am
J am what I am
J#am what I am
J#am what I bm
J#am what I#bm
J#am what#I#bm
J#am what#I bm
J#am whaw#I bm
J am whaw#I bm
J am what#I bm
J am what#I#bm
J am what#J#bm
I am what#J#bm
J am what#J#bm

相关内容

  • 没有找到相关文章

最新更新