Использование имплицитов для ключей карты scala

Может ли кто-нибудь сказать мне, почему, как показано ниже, неявное преобразование работает при простом создании объекта KeyVal, но не работает при создании ключа в карте, которая является KeyVal.

Спасибо.

object o {
  case class KeyVal(i: Int)
  object KeyVal {
    implicit def strToKeyVal(s:String) = KeyVal(s.toInt)
  }
}

import o._

val x : KeyVal = "1"  // Works fine to create a KeyVal

val x : Map[KeyVal, String] = Map("1" -> "One") // Type Mismatch: found (String, String), wants (KeyVal, String)

person user1922871    schedule 03.07.2013    source источник


Ответы (2)


Компилятор Scala не всемогущ, и он не может разрешить все типы ошибок типов. Как он должен преобразовать кортеж (String, String) в кортеж (KeyVal, String) и почему не в (String, KeyVal) или (KeyVal, KeyVal). Ваше неявное преобразование преобразует String в KeyVal, но не (String, String) в KeyVal. Если вы добавите это неявное преобразование в объект-компаньон:

implicit def strToKeyVal(s: (String, String)): (KeyVal, String) = (KeyVal(s._1.toInt), s._2)

все будет работать нормально

person 4lex1v    schedule 03.07.2013
comment
Спасибо. Я предполагаю, что ожидать, что он узнает, что нужно преобразовать только первый член кортежа, было слишком. Однако я не думал, что это было так неразумно, поскольку он должен был знать, что первым членом кортежа был KeyVal, поскольку значение было Map[KeyVal,String] - person user1922871; 03.07.2013

Это просто вопрос времени. К тому времени, когда будет рассмотрен тип Map, у вас уже будет не String, а кортеж (String, String). Это происходит потому, что -> — это оператор, который применяется первым, а затем его результат возвращается для Map.

Если вы избегаете использования этого оператора, он работает:

val x : Map[KeyVal, String] = Map(("1", "One"))
person Daniel C. Sobral    schedule 03.07.2013
comment
Это имеет смысл. Альтернативой, которую я придумал, было использование неявного класса KeyVal(s: String), у которого есть метод: def hold(contents: String) = (this ->contents). Тогда карту можно определить как Map[KeyVal, String] = Карта (1 содержит единицу). Это работает для меня, поскольку KeyVal на самом деле представляет собой лунки на тарелке, поэтому он говорит, что в лунке содержится некоторое содержимое. Спасибо всем за хорошие ответы. - person user1922871; 04.07.2013