简体   繁体   English

Scala:奇怪的类型不匹配错误

[英]Scala: strange type mismatch error

Let's say I have a function like this (it's only an example, so do not offer me better ways to create 0,1,2,... style array): 假设我有一个像这样的函数(这只是一个例子,所以不要为我提供创建0,1,2,...样式数组的更好方法):

def createArray(size: Int): Array[Int] = {
  for (i <- 0 until size) yield i
}

But the compiler get upset with some mysterious type mismatch error: 但是编译器会因一些神秘的类型不匹配错误而感到沮丧:

(fragment of compare-images.scala):39: error: type mismatch;
 found   : RandomAccessSeq.Projection[Int]
 required: Array[Int]
      for (i <- 0 until size) yield i
            ^
one error found
!!!
discarding <script preamble>

I'm sure, the reason has something to do with the fact that until method's return type is Range , not Array . 我敢肯定,原因与以下事实有关: until方法的返回类型为Range ,不是Array Yet, why the compiler can't just cast the types? 但是,为什么编译器不能只转换类型? Interestingly the problem goes away when I remove the return type of my function: 有趣的是,当我删除函数的返回类型时,问题消失了:

def createArray(size: Int) = {
  for (i <- 0 until size) yield i
}

But I want my function to return Array ... 但是我希望我的函数返回Array ...

I also have another function, which goes like this: 我还有另一个功能,如下所示:

def screateArray2: Array[Int] = {
  val a = Array(1,2,3,4,5)
  for (i <- a) yield i
}

It compiles without any problems. 它编译没有任何问题。 It yields values very similarly to the first example, but doesn't use until method... 它产生的值与第一个示例非常相似,但是直到方法...才使用。

Am I missing something about Scala's type system? 我是否缺少有关Scala的类型系统的信息?

I'm quite new to Scala. 我是Scala的新手。

EDIT: I sort of solved my problem like this: 编辑:我有点解决了这样的问题:

def crop(data: Array[Int]): Array[Int] = (
  for (i <- 0 until data.size) yield i
).toArray

But in my view it's anything but readable... 但在我看来,它几乎没有可读性...

You can't cast the types just because an Array is not a Range, nor a superclass of it. 您不能仅仅因为数组既不是范围也不是它的超类而强制转换类型。 I think their most common supertype would be IndexedSeq . 我认为它们最常见的超类型将是IndexedSeq So your example would be similar to a method which you declare to return an Int, while the implementation would return a String, for instance. 因此,您的示例将类似于您声明返回Int的方法,而实现将返回例如String。 Range does have a toArray method, however, so if you want to use the until style and return an Array, you can do it like this: Range确实具有toArray方法,因此,如果要使用直到风格并返回Array,可以这样进行:


scala> (for (i <- 0 until 5) yield i).toArray
res0: Array[Int] = Array(0, 1, 2, 3, 4)

or, if do don't like this, there's another way, but that doesn't use the until style: 或者,如果不喜欢,还有另一种方法,但是不使用直到风格:


scala> for (i <- Array.range(0,5)) yield i          
res1: Array[Int] = Array(0, 1, 2, 3, 4)

Also, check this related question for returning custom types from a for comprehension 另外,请检查此相关问题以从中返回自定义类型以进行理解

So, How about this one: 那么,这个呢?

scala> import scala.collection.breakOut
import scala.collection.breakOut

scala> def createSet(size: Int): Set[Int] = (
     |     for(i <- 0 until size) yield i
     | )(breakOut)
createSet: (size: Int)Set[Int]

scala> def createList(size: Int): List[Int] = (
     |     for(i <- 0 until size) yield i
     | )(breakOut)
createList: (size: Int)List[Int]

scala> def createArray(size: Int): Array[Int] = (
     |     for(i <- 0 until size) yield i
     | )(breakOut)
createArray: (size: Int)Array[Int]

scala> createArray(10)
res3: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> createList(5)
res4: List[Int] = List(0, 1, 2, 3, 4)

scala> createSet(4)
res5: Set[Int] = Set(0, 1, 2, 3)

scala>

Arjan's solution can be shortened to: Arjan的解决方案可以简化为:

 def createArray(size: Int) = (0 until size).toArray

[Edit] Of course you can remove values you don't need before you create the array [编辑]当然,您可以在创建数组之前删除不需要的值

 def createArray(size: Int) = (0 until size).filter(LOTSOFINTERESTINGSTUFF).toArray

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM