Scala изменить параметры функции, определенные в признаке - PullRequest
0 голосов
/ 20 сентября 2018

Поскольку я нигде не нашел решения своей проблемы, я думаю, что мог бы думать в очень неправильном направлении.

Вот моя проблема: у меня есть черта A и другая черта B и сопутствующие объектыAB1, AB2, AB3 и так далее.Одноэлементные объекты расширяют черту A, а классы расширяют черту B. Многие объекты этих классов находятся в списке.

В этих объектах я хочу использовать функции, определенные в соответствующем одноэлементном объекте, которые принимают объекты одного и того же класса.как объект-одиночка.

Это пример для черт:

trait A {
    def compare(firstB: B, secondB: B) : Int
}

trait B {}

И сопутствующих объектов:

class AB1(val variable: Int) extends B {}

object AB1 extends A {
    def apply(list: List[Int]): Option[AB1] = {
        if(list.foldLeft(0)(_ + _) < 10 && list.nonEmpty)
            some(new AB1(list.head))
        else
            null
    }
    override def compare(ab11: AB1, ab12: AB1): Int = {
        if(ab11 > ab12) 
            1
        else if(ab11 > ab12) 
            -1
        else 
            0
    }
}

и

class AB2(val variable1: Int, val variable2: Int) extends B {}

object AB2 extends A {
    def apply(list: List[Int]): Option[AB1] = {
        if(list.foldLeft(0)(_ + _) < 20 && list.length >= 2)
            some(new AB1(list.head, list.tail.head))
        else
            null
    }
    override def compare(ab21: AB2, ab22: AB2): Int = {
        if(ab11 > ab12) 
            10
        else if(ab11 > ab12) 
            -10
        else 
            0
    }
}

Итак, я уже отфильтровал некоторые объекты и поместил «реальные» объекты в список, назовем его bList.Для каждого элемента списка я хочу вызвать функцию сравнения.

Я думаю, это выглядело бы примерно так:

val bList: List[B]
val a = getA(bList.head) // getA should be a function that returns the companion object of a class
a.compare(bList.head, bList.tail.head)

На своем пути я столкнулся с двумя проблемами:

  1. b.getClass не равно AB1.getClass, когда b является объектом класса AB1.Но это не моя главная проблема.Я нашел решение с использованием сравнения строк, которое на самом деле не очень красиво, но на данный момент оно работает.
  2. Функция compare должна быть определена в признаке, потому что в противном случае она не может быть приведена ни к какомуодноэлементный объект, который расширяет черту A. Но я не могу определить функцию с параметрами типа переменной.

Я действительно надеюсь, что вы можете помочь мне с этой проблемой!

РЕДАКТИРОВАТЬ : Теперь я вижу, что забыл упомянуть кое-что:

Я думаю, что мне нужно немного углубиться в то, что я пытаюсь сделать, чтобы вы поняли мою проблему:

У меня есть List[List[C]].Список этих C может быть способен создать объект AB1 с ним, но может быть AB2, или, возможно, AB3 и так далее.Так что у меня есть

val c: List[C] = (C1, C2, C4)
val aList: List[A] = (AB1, AB2, AB3, ...)
val bestB: B = (for{
    element <- aList
} yield element  (c)).flatten.head   // Because the List aList is ordered: AB1 is the best case, AB2 the second best and so on.

Я делаю это для каждого Списка [C] из Списка [List [C]].Так что в итоге у меня может быть List[B] = (AB3, AB1, AB2, AB1) (например).Из этого списка я хочу сначала получить «лучшие» B с в порядке aList, а затем я получу List[B] = (AB1, AB1).Эти два AB1 я хочу сравнить, а затем поместить «лучший» элемент (согласно функции сравнения соответствующего объекта) или оба в новый список.Это то, чего я хочу достичь.

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Если честно, я все еще путаюсь с тем, в чем ваша корневая проблема.Но я попытаюсь ответить на то, что я понял.

Во-первых, если вы хотите изменить тип аргументов при переопределении функции из признака.Тогда ответ: Вы не можете! - потому что это нарушило бы Принцип замещения Лискова .

Но вы можете достичь того, что вы хотите, с помощью Тип Class .

trait B {}

trait BComparator[Bi <: B] {
  def compare(firstB: Bi, secondB: Bi): Int
}

Теперь, если вам нужен способ динамически получить правильный экземпляр BComparator для ваших подклассов, вы можете сделать эти экземпляры неявными значениями в их сопутствующих объектах.

class B1 extends B {}
object B1 {
  implicit val B1Comparator: BComparator[B1] = new BComparator[B1] {
    override def compare(firstB: B1, secondB: B2): Int = ???
  }
}

Теперь, учитывая b11 и b12 как экземпляры B1, вы можете просто написать

implicitly[BComparator[B1]].compare(b11, b12)
0 голосов
/ 20 сентября 2018

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

trait B
case class AB1(variable: Int) extends B
case class AB2(variable1: Int, variable2: Int) extends B

implicit object AB1Comparator extends Comparator[AB1] {
  override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}

implicit object AB2Comparator extends Comparator[AB2] {
  override def compare(o1: AB2, o2: AB2): Int = java.lang.Integer.compare(o1.variable1, o2.variable1) match {
    case 0 => java.lang.Integer.compare(o1.variable2, o2.variable2)
    case other => other
  }
}

def compare[A](obj1: A, obj2: A)(implicit comparator: Comparator[A]) = {
  comparator.compare(obj1, obj2)
}

val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1Compare = compare(ab1List.head, ab1List.tail.head)

val ab2List = List(AB2(1, 1), AB2(1, 1), AB2(1, 3))
val ab2Compare = compare(ab2List.head, ab2List.tail.head)

Или, если вы хотите отсортировать список, вы должны использовать Ordering:

trait B
case class AB1(variable: Int) extends B

implicit object AB1Ordering extends Ordering[AB1] {
  override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}
val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1ListSorted = ab1List.sorted
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...