Scala Pattern Matching возвращает ожидаемый тип, но впоследствии генерирует несоответствие типов - PullRequest
0 голосов
/ 09 мая 2018

У меня есть следующее определение объекта 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. Что я могу сделать, чтобы исправить мой код?

Заранее спасибо, это заставило меня несколько часов биться головой!

РЕДАКТИРОВАТЬ

Хорошо, так что, опираясь на информацию @Alex Savitsky и @Jakub Zalas (спасибо, ребята), я существенно изменил исходный код, чтобы, как я надеюсь, что-то более функционально ориентированное, что может иметь дело со смешанными типами значений инициализации:

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

Будучи новичком в Scala (и Java) из Python, я все еще борюсь с функциональными и статическими аспектами типизации, поэтому любые комментарии / предложения с благодарностью принимаются.

Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Вы можете преобразовать аргументы в соответствующие типы на лету, а затем сопоставить всю коллекцию сразу:

// 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)
0 голосов
/ 09 мая 2018

Соответствие шаблону, которое вы определили, не разрешается в один тип:

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

Результат может быть либо Int, либо Boolean, поэтому тип 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
}
...