Как добавить метод расширения к одноэлементному объекту в scala 2?

Я наткнулся на эту тему, и там @prolativ предоставил какой-то причудливый синтаксис scala 3 для создания методов расширения для объектов.

extension (int: Int.type)
  def unapply(s: String): Option[Int] = s.toIntOption

Но это заставило меня задуматься, есть ли способ сделать что-то подобное в scala 2?

я пробовал

implicit class IntOps(s: Int.type) {
  def unapply(s: String): Option[Int] = s.toIntOption
}

Который казался просто переводом scala 2, но он не компилируется с ошибкой object Int is not a case class, nor does it have a valid unapply/unapplySeq member.

УПД В случае сопоставления с образцом есть способ сделать это - просто добавьте новый объект и сопоставьте его:

object IntOps {
  def unapply(s: String): Option[Int] = s.toIntOption
}

но остается вопрос - как добавить методы расширения к объекту?

Int.type — это правильный способ добавить методы расширения к объекту-компаньону типа Int. Просто кажется, что вы не можете добавить unapply в качестве расширения в Scala 2.
Luis Miguel Mejía Suárez 30.03.2023 15:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
118
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Неявный класс — это правильный способ добавить метод расширения к объекту.

implicit class IntOps(obj: Int.type) {
  def parse(s: String): Option[Int] = s.toIntOption
}

Int.parse("123") // Some(123)

И unapply можно добавить таким же образом

implicit class IntOps(obj: Int.type) {
  def unapply(s: String): Option[Int] = s.toIntOption
}

Int.unapply("123") // Some(123)

Просто это не повлияет на сопоставление с образцом

"123" match {
  case Int(i) => ??? // doesn't compile: object Int is not a case class, nor does it have a valid unapply/unapplySeq member
}

Место, где компилятор Scala 2 выбрасывает object Int is not a case class, nor does it have a valid unapply/unapplySeq member, находится здесь: https://github.com/scala/scala/blob/v2.13.10/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala#L121-L122

else if (!reallyExists(member))
  CaseClassConstructorError(fun, s"${fun.symbol} is not a case class, nor does it have a valid unapply/unapplySeq member")

Это основано на символах (что-то вроде typeOf[Int.type].decl(TermName("unapply")) в терминах scala-reflect). Неявные преобразования (методы расширения) здесь не проверяются.

Это изменено в Scala 3: https://github.com/lampepfl/dotty/blob/3.2.2/compiler/src/dotty/tools/dotc/typer/Applications.scala#L1291-L1341 Компилятор пытается для проверки типов x.unapply, включая неявные преобразования.

Кстати, когда компилятор Scala 2 решает, генерировать ли unapply в сопутствующем объекте case-класса (Int не был case-классом), компилятор также не проверяет методы расширения

Как посмотреть код, который Scala использует для автоматической генерации функции применения для классов кейсов?

case class MyClass(i: Int)

MyClass(42) match {
  case MyClass(i) => println(i) // 42
}
case class MyClass(i: Int)
object MyClass {
  def unapply(mc: MyClass): Option[Int] = Some(100)
}

MyClass(42) match {
  case MyClass(i) => println(i) // 100
}
case class MyClass(i: Int)

implicit class MyClassCompanionOps(mc: MyClass.type) {
  def unapply(mc: MyClass): Option[Int] = Some(100)
}

MyClass(42) match {
  case MyClass(i) => println(i) // 42
}

И это поведение такое же в Scala 3.


Как расширить String, чтобы добавить новую функцию неприменения для использования при извлечении?

обогатите PartialFunction функцией неприменения

Другие вопросы по теме