Итак, у меня был очень простой класс case:
case class StreetSecondary1(designator: String, value: Option[String])
Это работало отлично. Тем не менее, у меня были места, где я разбирал одну строку в кортеж, который затем использовался для создания экземпляра этого класса case:
def parse1(values: String): StreetSecondary1 = {
val index = values.indexOf(" ")
StreetSecondary1.tupled(
if (index > -1)
//clip off string prior to space as designator and optionally use string after space as value
(values.take(index), if (values.size > index + 1) Some(values.drop(index + 1)) else None)
else
//no space, so only designator could have been provided
(values, None)
)
}
Итак, я хотел реорганизовать все разные места с помощью этого же кода синтаксического анализа в класс case, как это (но это не будет компилироваться):
case class StreetSecondary2(designator: String, value: Option[String]) {
def this(values: String) = this.tupled(parse(values))
private def parse(values: String): (String, Option[String]) = {
val index = values.indexOf(" ")
if (index > -1)
//clip off string prior to space as designator and optionally use string after space as value
(values.take(index), if (values.size > index + 1) Some(values.drop(index + 1)) else None)
else
//no space, so only designator could have been provided
(values, None)
}
}
Похоже, что возникает проблема с цыпленком/яйцом при добавлении конструктора класса case И с функцией, которая принимает параметр и преобразует их перед вызовом фактического конструктора. Я возился с этим (идя по многим касательным). Затем я прибег к попытке пути сопутствующего объекта:
object StreetSecondary3 {
private def parse(values: String): (String, Option[String]) = {
val index = values.indexOf(" ")
if (index > -1)
//clip off string prior to space as designator and optionally use string after space as value
(values.take(index), if (values.size > index + 1) Some(values.drop(index + 1)) else None)
else
//no space, so only designator could have been provided
(values, None)
}
def apply(values: String): StreetSecondary3 = {
val tuple: (String, Option[String]) = parse(values)
StreetSecondary3(tuple._1, tuple._2) //Why doesn't .tupled method work here?
}
}
case class StreetSecondary3(designator: String, value: Option[String])
Что я делаю неправильно в StreetSecondary2? Есть ли способ заставить его работать? Разумеется, должен быть более простой способ, когда мне не нужно добавлять все шаблоны сопутствующих объектов, присутствующие в StreetSecondary3. Есть?
Спасибо за любые отзывы и рекомендации, которые вы можете мне дать.
ОБНОВЛЕНИЕ
Уф! Уже много уроков.
A) метод parse StreetSecondary2 не использует неявный контекст "this" в создаваемом экземпляре класса case (т.е. является статическим методом в терминах Java), поэтому он лучше перемещается в объект-компаньон.
B) К сожалению, при составлении явного сопутствующего объекта для класса case компилятор, предоставляющий "неявный сопутствующий объект", теряется. Метод пополнения (и другие, я угадываю - конечно, пожелал, чтобы был способ сохранить его и увеличить, в отличие от его удаления) содержались в компиляторе, снабженном "неявным сопутствующим объектом" и не предоставляемом в новом явном сопутствующем объекте. Это было исправлено добавлением "extends ((String, Option [String]) = > StreetSecondary) к явному сопутствующему объекту.
C) Здесь обновленное решение (которое также включает более краткий вариант функции синтаксического анализа с благодарностью Габриэле Петронелле):
object StreetSecondary4 extends ((String, Option[String]) => StreetSecondary4) {
private def parseToTuple(values: String): (String, Option[String]) = {
val (designator, value) = values.span(_ != ' ')
(designator, Option(value.trim).filter(_.nonEmpty))
}
def apply(values: String): StreetSecondary4 =
StreetSecondary4.tupled(parseToTuple(values))
}
case class StreetSecondary4(designator: String, value: Option[String])
Это едва лучше с точки зрения шаблона, чем версия StreetSecondary3. Тем не менее, теперь это становится немного более ощутимым из-за того, что явный контекстный контекст стал явным.