Scala模式匹配返回预期的类型,但随后生成类型不匹配

Scala模式匹配返回预期的类型,但随后生成类型不匹配,scala,types,pattern-matching,Scala,Types,Pattern Matching,我有以下scala对象定义: case class RecursiveSettings ( var recursiveFrom: Int, var recursiveTo: Int, var nonRecursiveFrom: Int, var nonRecursiveTo: Int, var betweenReach: Int, var scoresamephrase: Boolean ) 我试图从ArrayBuffer中获取变量: i

我有以下scala对象定义:

case class RecursiveSettings (
    var recursiveFrom: Int,
    var recursiveTo: Int,
    var nonRecursiveFrom: Int,
    var nonRecursiveTo: Int,
    var betweenReach: Int,
    var scoresamephrase: Boolean
    )
我试图从ArrayBuffer中获取变量:

import scala.collection.mutable.ArrayBuffer

def main(args: Array[String]){
    var settings = List("","1", "2", "0", "0", true)
    var newsettings = new ArrayBuffer[Any]

    println(settings)

    settings.foreach {a =>
        val z = a match{
            case "" => 0
            case s : String => s.toInt
            case _  => a
        }
        newsettings += z
    }
    println(newsettings)

    var result = new RecursiveSettings(0,0,0,0,0,true)
    println(result)

    for (i <- 0 to (newsettings.length - 1)){
        println("newsettings_i", newsettings(i))

        val x = newsettings(i) match{
            case y : Int => y
            case y : Boolean => y
            case _ => 0
        }
        println("x:", x)
        i match{
            case 0 => result.recursiveFrom = x
            case 1 => result.recursiveTo = x
            case 2 => result.nonRecursiveFrom = x
            case 3 => result.nonRecursiveTo = x
            case 4 => result.betweenReach = x
            case 5 => result.scoresamephrase = x
        }
    }
}
但是,当我将“我匹配”语句添加回时,我收到了很多此类投诉:

~/match.scala:44: error: type mismatch;
found   : AnyVal
required: Int
            case 0 => result.recursiveFrom = x
有人能帮我理解一下:

  • 为什么简单类型匹配会产生所需的结果,但不会传递到对象

  • 如何更正代码

  • 提前谢谢,这让我头痛了好几个小时

    编辑

    好的,基于@Alex Savitsky和@Jakub Zalas(谢谢大家)的信息,我已经对原始代码进行了实质性的修改,希望它能更面向功能,能够处理混合的init值类型:

    object matcher2{
    def main(args: Array[String]):Unit = {
    
        val init = Array("",1, "4", null, "0", false)
        matchf(init)
    }
    def matchf(args : Array[_] ) : RecursiveSettings = {
        val settings : RecursiveSettings = args.map{
            case "" => 0
            case "true" => true
            case "false" => false
            case b : Boolean => b
            case s : String => s.toInt
            case i : Int => i
            case null => 0
    
        } match {
            case Array(recursiveFrom: Int, recursiveTo: Int, nonRecursiveFrom: Int, nonRecursiveTo: Int, betweenReach: Int, scoresamephrase: Boolean) =>
            RecursiveSettings(recursiveFrom, recursiveTo, nonRecursiveFrom, nonRecursiveTo, betweenReach, scoresamephrase)
        }
        println(settings)
        settings
    }
    }
    
    作为Python中Scala(和Java)的新手,我在函数和静态类型方面仍有相当大的困难,所以我非常感谢您的评论和建议


    感谢您的帮助。

    您定义的模式匹配不能解析为单一类型:

    val x=newsettings(i)匹配{
    案例y:Int=>y
    案例y:布尔=>y
    大小写=>0
    }
    
    结果可以是
    Int
    Boolean
    ,因此
    x
    的类型将是
    AnyVal
    ,因为Scala无法推断单一类型

    快速(脏)解决方案

    修复代码而不进行大量修改的最简单方法可能是显式地将
    x
    转换为预期类型:

    i匹配{
    案例0=>result.recursiveFrom=x.asInstanceOf[Int]
    案例1=>result.recursiveTo=x.asInstanceOf[Int]
    案例2=>result.nonRecursiveFrom=x.asInstanceOf[Int]
    案例3=>result.nonRecursiveTo=x.asInstanceOf[Int]
    案例4=>result.betweenReach=x.asInstanceOf[Int]
    案例5=>result.scoresamephrase=x.asInstanceOf[Boolean]
    }
    
    更好的解决方案

    我建议您尝试使用不可变的数据结构重新设计代码,并尝试使用更实用的方法来解决问题。这样,您的代码将更具可读性,并且不易产生副作用

    例如,通过设置创建新闻设置的方式可以简化很多:

    val设置=列表(“,“1”,“2”,“0”,“0”,真)
    val newsettings=设置映射{
    案例“”=>0
    大小写s:String=>s.toInt
    案例a=>a
    }
    
    您可以动态地将参数转换为适当的类型,然后立即匹配整个集合:

    // assuming your args is an array of ["", "1", "2", "0", "0", "true"]
    val settings: RecursiveSettings = args.map {
        case "" => 0
        case "true" => true
        case "false" => false
        case s: String => s.toInt
    } match {
        case Array(recursiveFrom: Int, recursiveTo: Int, nonRecursiveFrom: Int, nonRecursiveTo: Int, betweenReach: Int, scoresamephrase: Boolean) =>
            RecursiveSettings(recursiveFrom, recursiveTo, nonRecursiveFrom, nonRecursiveTo, betweenReach, scoresamephrase)
    }
    
    您还可以匹配部分提供的参数,只要您决定哪些参数将接收默认值(此案例可与“完整”案例匹配一起使用):


    谢谢@JakubZalas是的,这已经解决了问题,我理解其中的原因,尽管我知道正如你所说,Scala中的类型转换是肮脏的。对于我自己的学习,如果你或其他人有时间,我有兴趣看到一个更优雅的解决方案。再次感谢。很高兴我能帮忙。不要犹豫接受答案。我提出了一个改进建议,可以让你知道该去哪里。我真的不知道你想解决什么问题来建议最好的最终解决方案。你能做的最好的事情就是努力改进你的代码,并在你进步的过程中问更多的问题。另外,这是stackoverflow,您应该努力;)完成;)感谢您让我开始,最后是我在寻找的数组上的大小写匹配。为了跟进@JakubZelas答案中的建议,可以更简单地通过模式匹配列表来实现:
    val first::second::third::fourth::fifth::Nil=list(“,”1“,”2“,”3“,true)
    ,然后定义一个函数来转换字符串(调用if
    f
    ),然后定义递归设置(f(first),f(second),…,fifth)。顺便说一句,请查看这篇阿尔文·亚历山大的文章,这篇文章非常有用,是@hoyland的起点,谢谢。这个答案非常有用,谢谢。唯一的问题是数组[String]不允许我处理包含布尔值的OP case。我添加了一个编辑,说明了我选择的处理方法。再次感谢。我假设
    Array[String]
    是您尝试转换的
    main
    方法的原始
    args
    。如果情况并非如此,并且您已经从一个
    列表[Any]
    开始,那么您完全可以不进行
    布尔
    转换(只剩下
    Int
    转换),并且将
    匹配
    列表上的
    而不是
    数组
    ;除此之外,代码将只是后续的sameThanks。是的,“List[Any]”在混合大小写中对我有效,但在纯字符串大小写中出现了类型错误。原始数据来自用户通过db接口输入的数据,我还没有构建该接口,并使用“Document.get()”下拉,因此可以是任何类型。。。这就是为什么我最终选择了“数组”。。。如果这是有意义的话……这是完全有意义的,因为
    Array[\u]
    相当于
    Array[Any]
    ,非常适合存储各种类型。至于类型错误(我假设这些是不是
    Integer
    s的
    String
    s的转换错误),您可以使用
    scala.util.control.Exception.allCatch
    字符串
    转换为
    整数
    (如果可以转换),或者将其保留为
    String
    (如果不能转换)以实用的方式感谢@Alex,所有这些都非常有用。很抱歉,我无法正确地更新您的答案-等待足够的代表!)
    object matcher2{
    def main(args: Array[String]):Unit = {
    
        val init = Array("",1, "4", null, "0", false)
        matchf(init)
    }
    def matchf(args : Array[_] ) : RecursiveSettings = {
        val settings : RecursiveSettings = args.map{
            case "" => 0
            case "true" => true
            case "false" => false
            case b : Boolean => b
            case s : String => s.toInt
            case i : Int => i
            case null => 0
    
        } match {
            case Array(recursiveFrom: Int, recursiveTo: Int, nonRecursiveFrom: Int, nonRecursiveTo: Int, betweenReach: Int, scoresamephrase: Boolean) =>
            RecursiveSettings(recursiveFrom, recursiveTo, nonRecursiveFrom, nonRecursiveTo, betweenReach, scoresamephrase)
        }
        println(settings)
        settings
    }
    }
    
    // assuming your args is an array of ["", "1", "2", "0", "0", "true"]
    val settings: RecursiveSettings = args.map {
        case "" => 0
        case "true" => true
        case "false" => false
        case s: String => s.toInt
    } match {
        case Array(recursiveFrom: Int, recursiveTo: Int, nonRecursiveFrom: Int, nonRecursiveTo: Int, betweenReach: Int, scoresamephrase: Boolean) =>
            RecursiveSettings(recursiveFrom, recursiveTo, nonRecursiveFrom, nonRecursiveTo, betweenReach, scoresamephrase)
    }
    
        case Array(recursiveFrom: Int, recursiveTo: Int) =>
            RecursiveSettings(recursiveFrom, recursiveTo, 0, 2, 1, true)