Scala错误迭代for循环中的映射列表

时间:2015-11-27 05:27:06

标签: scala

我正在学习scala,并对我得到的错误感到困惑。我正在尝试使用不同的容器,目前我有一个地图列表,每个地图共享相同的键。我正在尝试使用for循环遍历列表并将对应于键“startlocation”的值放入Node类型的数组中(我制作的类),但我似乎无法正确使用语法。当我试图从列表中的当前地图获取该键的值时,它告诉我我的密钥是一个不正确的参数。

此代码有什么问题,我该怎么做才能修复它?

class Node{
     var visited = false;
     var mDistance = 10000;
     var prevLoc = " ";
}

object test{
  def main(args: Array[String]){

    var i = 0;
    var l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10), 
                Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));
   var b = new Array[Node](l.size);       
   var index = 0;
   for(i <- l){

       b(index).prevLoc = i("startlocation");    // This is the line where the error occurs
       index++;
    }


 }
}

特定错误:类型不匹配;发现:任何必需:字符串

此错误突出显示了我在上面评论的行中的“startlocation”。

3 个答案:

答案 0 :(得分:5)

错误

异质地图

首先,地图定义存在很大问题。由于您使用IntString作为值类型,因此结果类型被推断为这些值的最可能的具体公共超类型,Any,因为String和{{1非常不同。

正确的做法?看起来您的地图有意预设了一组密钥,这些密钥在scala中通过Int es甚至更好class更好地实现,因此您可以定义case class类附近

Node

以后

case class Route(startLocation: String, endLocation: String, distance: Int)

甚至

val l = List(
  Route( startLocation = "Kruthika's abode",  endLocation = "Mark's crib", distance = 10),
  Route( startLocation = "Mark's Crib", endLocation = "Kirk's Farm", distance = 9))

最后

val l = List(
      Route( "Kruthika's abode", "Mark's crib",  10),
      Route( "Mark's Crib", "Kirk's Farm",  9))

++

scala中没有postfix b(index).prevLoc = i.startLocation // This is the line where the error occurs 运算符,因此++至少应为index++

样式指南

index += 1 iables

您经常可以避免var定义。

例如var过多,因为它甚至没有在您的代码中使用 因为在var i = 0;中创建了新的for(i <- l)定义,该定义仅在循环内有效

此外,您可以避免i的定义,您可以使用索引迭代收集

var index

不变性

同样,你经常可以避免for((i, index) <- l.zipWithIndex) 中的var iables,使类不可变。您可以在每次需要时创建新实例(可能是class exisitng)而不是变异。

这对您的代码至关重要,因为.copy()肯定会抛出b(index).prevLoc,因为在您的数组中没有创建NullPointerException的实例。

想象一下你定义了

Node

使用就是

case class Node(visited: Boolean = false,  mDistance: Int  = 10000, prevLoc: String = " ")

Node(prevLoc = i.startLocation) (列出序列≺monad)理解

最后,您的for现在可以翻译为b不可变val,因为List是从现有的for创建新集合的表达式。有了这样的声明,您甚至不需要知道当前索引,因此您可以删除建议的yield部分

.zipWithIndex

最后 - 大多数时候你几乎可以在行尾避免;

总结一下,整个代码可以翻译成

;

您可以将case class Node(visited: Boolean = false, mDistance: Int = 10000, prevLoc: String = " ") case class Route(startLocation: String, endLocation: String, distance: Int) object test{ def main(args: Array[String]){ val l = List( Route( "Kruthika's abode", "Mark's crib", 10), Route( "Mark's Crib", "Kirk's Farm", 9)) val b = for(i <- l) yield Node(prevLoc = i.startLocation) } } 添加到println(b)方法的末尾,以查看如何打印mainList

答案 1 :(得分:2)

这是因为你在地图中混合了String和Int类型。 'prevLoc'似乎是一个String,但你的地图包含Any(scala编译器推断这种类型,因为你没有指定任何类型)。

我建议您将地图显式设为Map[String, String]。在这种情况下,您的程序将无法编译(您有一些整数作为地图值,您可以执行"distance" -> 10.toString之类的操作。)

P.S。尽量避免使用var:可以使用不可变变量(val s)和mapfilter,{{1}等函数编写没有它的Scala代码以功能的方式。

答案 2 :(得分:1)

你可以这样试试,

val l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10), 
            Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));

case class Node(visited:Boolean = false, mDistance:Int = 10000, prevLoc:String)

l.map(x=>Node(prevLoc = x("startlocation").asInstanceOf[String]))