Scala Pattern Matching返回预期类型,但之后会生成类型不匹配

时间:2018-05-09 09:56:14

标签: 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中获取变量:

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
        }
    }
}

如果我注释掉i match语句并进行简单的类型匹配:

for (i <- 0 to (newsettings.length - 1)){
        println("newsettings_i", newsettings(i))
        val x = newsettings(i) match{
            case y : Int => "Int"
            case y : Boolean => "Bool"
            case _ => 0
        }
        println("x:", x)

代码编译,运行并得到:

List(, 1, 2, 0, 0, true)
ArrayBuffer(0, 1, 2, 0, 0, true)
RecursiveSettings(0,0,0,0,0,true)
(newsettings_i,0)
(x:,Int)
(newsettings_i,1)
(x:,Int)
(newsettings_i,2)
(x:,Int)
(newsettings_i,0)
(x:,Int)
(newsettings_i,0)
(x:,Int)
(newsettings_i,true)
(x:,Bool)

但是当我添加i match语句时,我得到了很多关于这种类型的抱怨:

~/match.scala:44: error: type mismatch;
found   : AnyVal
required: Int
            case 0 => result.recursiveFrom = x

有人可以帮我理解:

  1. 为什么简单类型匹配会产生所需的结果,但这不会传递给对象?

  2. 我该怎么做才能纠正我的代码?

  3. 先谢谢,这让我头疼了好几个小时!

    编辑

    好的,基于来自@Alex Savitsky和@Jakub Zalas的信息(感谢大家)我已经将原始代码大幅修改为我希望能够处理混合初始值类型的更具功能性的东西: / p>

    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)我仍然在功能和静态类型方面苦苦挣扎,所以感谢任何评论/建议。

    感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

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

val x = newsettings(i) match {
    case y : Int => y
    case y : Boolean => y
    case _ => 0
}

结果可以是IntBoolean,因此x的类型将为AnyVal,因为Scala无法推断出单一类型。

快速(和肮脏)解决方案

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

i match {
    case 0 => result.recursiveFrom = x.asInstanceOf[Int]
    case 1 => result.recursiveTo = x.asInstanceOf[Int]
    case 2 => result.nonRecursiveFrom = x.asInstanceOf[Int]
    case 3 => result.nonRecursiveTo = x.asInstanceOf[Int]
    case 4 => result.betweenReach = x.asInstanceOf[Int]
    case 5 => result.scoresamephrase = x.asInstanceOf[Boolean]
  }

更好的解决方案

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

例如,您可以简化从设置中创建新设置的方式:

val settings = List("","1", "2", "0", "0", true)
val newsettings = settings map {
  case "" => 0
  case s : String => s.toInt
  case a  => a
}

答案 1 :(得分:1)

您可以动态地将参数转换为适当的类型,然后立即匹配整个集合:

// 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)