【问题标题】:Shuffling Range in Scala is OddScala中的洗牌范围很奇怪
【发布时间】:2015-05-08 20:04:09
【问题描述】:

查看这个 REPL 会话(为了便于阅读,我对其进行了整理):

scala> val x = 1 to 10
x: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val y = x.toSeq
y: Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> x eq y
res14: Boolean = true

scala> util.Random.shuffle(y)
<console>:10: error: Cannot construct a collection of type scala.collection.AbstractSeq[Int] with elements of type Int based on a collection of type scala.collection.AbstractSeq[Int].
              util.Random.shuffle(y)
                                 ^

scala> util.Random.shuffle(x)
res16: scala.collection.immutable.IndexedSeq[Int] = Vector(8, 3, 4, 2, 10, 9, 7, 5, 6, 1)

首先,无论类型不同,这都应该有效。 问题是“为什么?”

【问题讨论】:

    标签: scala range shuffle


    【解决方案1】:

    这是 SI-6948, a bug 由基本 scala 损坏引起的。

    这是一个nice long commit message 以及一些额外的解释。

    【讨论】:

    【解决方案2】:

    由于某种原因,shuffle 的类型推断会为 InclusiveRange 产生不同的结果。

    toSeq 导致 Range 的原因是它的定义无辜地缩小了类型:

    override def toSeq = this
    

    有一个悬而未决的问题是推断被覆盖方法的结果类型。

    表明 REPL 没有说谎:

    scala> import util.Random.shuffle
    import util.Random.shuffle
    
    scala> val x = 1 to 10
    x: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    scala> val y = x.toSeq
    y: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    scala> val z: Range = x
    z: Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    scala> shuffle(x)
    res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 5, 2, 10, 9, 6, 3, 7, 4, 8)
    
    scala> shuffle(y)
    <console>:11: error: Cannot construct a collection of type scala.collection.AbstractSeq[Int] with elements of type Int based on a collection of type scala.collection.AbstractSeq[Int].
                  shuffle(y)
                         ^
    

    截取以查看推断的内容和使用的隐含内容:

    scala> :replay -Xprint:typer
    
    Replaying: shuffle(x)
            private[this] val res0: scala.collection.immutable.IndexedSeq[Int] = scala.util.Random.shuffle[Int, scala.collection.immutable.IndexedSeq]($line5.$read.$iw.$iw.x)(immutable.this.IndexedSeq.canBuildFrom[Int]);
    
    scala> shuffle(y)
            private[this] val <res1: error>: <error> = scala.util.Random.shuffle[Int, scala.collection.AbstractSeq]($line6.$read.$iw.$iw.y)();
    

    而不是你希望的:

    scala> shuffle[Int, collection.immutable.IndexedSeq](z)
    res3: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 5, 3, 8, 4, 1, 2, 10, 7, 9)
    

    对于-Ytyper-debug,有一个额外的类型参数A 似乎让它继续处理Inclusive,但我不知道它是从哪里来的。

    |    |    |    |    |-- x BYVALmode-EXPRmode-POLYmode (site: value res3  in $iw) 
    |    |    |    |    |    \-> scala.collection.immutable.Range.Inclusive
    |    |    |    |    solving for (T: ?T, CC: ?CC)
    |    |    |    |    solving for (A: ?A)
    |    |    |    |    [adapt] [A]=> scala.collection.generic.CanBuildFrom[scala.collect... adapted to [A]=> scala.collection.generic.CanBuildFrom[scala.collect... based on pt scala.collection.generic.CanBuildFrom[scala.collection.immutable.IndexedSeq[Int],Int,scala.collection.immutable.IndexedSeq[Int]]
    |    |    |    |    |-- [T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: ... EXPRmode (site: value res3  in $iw) 
    |    |    |    |    |    \-> scala.collection.immutable.IndexedSeq[Int]
    |    |    |    |    [adapt] [T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: ... adapted to [T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: ...
    |    |    |    |    \-> scala.collection.immutable.IndexedSeq[Int]
    

    这是错误还是行为?

    说清楚:

    scala> import language.higherKinds, collection.TraversableOnce, collection.generic.CanBuildFrom
    import language.higherKinds
    import collection.TraversableOnce
    import collection.generic.CanBuildFrom
    
    scala> def f[T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit cbf: CanBuildFrom[CC[T],T,CC[T]]): CC[T] = null.asInstanceOf[CC[T]]
    f: [T, CC[X] <: scala.collection.TraversableOnce[X]](xs: CC[T])(implicit cbf: scala.collection.generic.CanBuildFrom[CC[T],T,CC[T]])CC[T]
    
    scala> f(1 to 10)
    res0: scala.collection.immutable.IndexedSeq[Int] = null
    
    scala> f(1 until 10)
    <console>:12: error: Cannot construct a collection of type scala.collection.AbstractSeq[Int] with elements of type Int based on a collection of type scala.collection.AbstractSeq[Int].
                  f(1 until 10)
                   ^
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-30
      • 1970-01-01
      • 2019-05-18
      • 1970-01-01
      • 2016-02-09
      • 1970-01-01
      相关资源
      最近更新 更多