Как переопределить equals для типов псевдонимов в scala - PullRequest
1 голос
/ 08 апреля 2019

Я использую псевдоним типа, как показано ниже:

trait IPAddress
object IPAddr {
  type IP = Array[Byte] with IPAddress
  type IPv4 <: IP
  type IPv6 <: IP
}

Здесь я хочу переопределить метод equals для типа IP.Как это можно сделать?

Ответы [ 3 ]

3 голосов
/ 08 апреля 2019

Ниже решение сделано с методом расширения ===:

  implicit class IPOps(ip: IP) {
    def ===(other: IP): Boolean = ip.sameElements(other)
  }

  trait IPAddress
  object IPAddr {
    type IP = Array[Byte] with IPAddress
    type IPv4 <: IP
    type IPv6 <: IP
  }

  val ip1 = InetAddress.getByName("1.2.3.4").getAddress.asInstanceOf[IP]
  val ip2 = InetAddress.getByName("1.2.3.4").getAddress.asInstanceOf[IP]
  println(ip1 === ip2) // true
0 голосов
/ 09 апреля 2019

Смысл этой конструкции в том, чтобы IP был точно представлен Array[Byte] во время выполнения и чтобы избежать упаковки / распаковки даже в тех случаях, когда классы значений не могут.

Это, естественно, означает, что он имеет больше ограничений, чем классы значений, и вы уже не можете переопределить equals для них:

C может не определять конкретные equals или hashCode методы.

Вы также не можете сделать это здесь. Вам просто нужно дать другому методу сравнения другое имя, как в ответе Алексея Новакова.

Обратите внимание, что технически asInstanceOf приведение не должно работать , и вы должны использовать тип уточнения, например

type IP = Array[Byte] { type T = IPAddress }
0 голосов
/ 08 апреля 2019

Я действительно удивлен, что подобный актерский состав вообще работает.Это не должно быть: Array и IP - это два совершенно разных типа, вы не должны быть в состоянии превращать одно в другое.Кроме того, Array также является окончательным, и вы не можете подкласс его.

Я попытался поиграться с этой «функцией» и заметил, что добавление к ней чего-либо более сложного (например, добавление типа self, такого как один из предложенных здесь ответов) приводит к сбою компилятора (2.11) ...

Кроме того, приведение вообще плохо, потому что оно обходит проверки типов во время компиляции.

Не делай этого.Вместо этого просто создайте класс-оболочку:

case class IPAddress(bytes: Array[Byte]) {
  override def equals(other: Any) = other match {
    case IPAddress(b) => b.sameElements(bytes)
    case _ => false
  }
}

Еще лучше, забудьте также обертку и просто используйте InetAddress вместо IP.Вы всегда можете получить от него байты, используя .getAddress по требованию.

...