2009-12-16 2 views
6

Сценарий: Я анализирую IL и хочу, например, преобразовать из представления на основе стека в CFG.Классы классов Scala в коллекциях

My IL состоит из нескольких операций, таких как PushInt (значение), Pop и т. Д. Вопрос в том, какая реализация будет правильной с точки зрения Scala. Я хотел бы использовать тематические классы/объекты или экстракторы, так что я могу написать код ALA

op match { 
    case PushInt(x) => doSomethingWith x 
    case Pop => ... 
} 

Теперь проблема существует с последовательностью, как PushInt(1) :: PushInt(1) :: Pop :: Pop так PushInt (1) равно PushInt (1), и я не могу добавьте несколько (равных) операций в коллекцию. Однако я знаю, что я выбрасываю некоторую информацию, которая является позицией в потоке, но она неявно сохраняется как индекс te в последовательности.

  • Одним из возможных решений является переопределить метод hashCode и нарушить правила равенства/hashCode. Я не очень доволен этим.

  • Другой вариант должен иметь «время создания» счетчик, который хранится в абстрактной базе, так что case class PushInt(value: Int) extends AbstractOp(AbstractOp.nextIndex)

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

Так что теперь мой вопрос заключается в том, как смоделировать мою структуру в соответствии с моими требованиями. Является ли какое-либо из возможных решений «правильным» с точки зрения Scala?

+1

Вы не можете добавить несколько одинаковых операций в коллекцию? Разве это не только в том случае, если коллекция представляет собой набор? –

+1

Нет, и еще хуже спросить indexOf в последовательности. Что, конечно, правильно, если объекты равны. –

+1

В списке можно, конечно, повторять одинаковые элементы. –

ответ

5

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

scala> trait AbstractOp 
defined trait AbstractOp 

scala> case class Pop() extends AbstractOp { 
    | override def equals(other: Any) = other match { 
    |  case that: Pop => this eq that 
    |  case _ => false 
    | } 
    | } 
defined class Pop 

scala> case class PushInt(val i: Int) extends AbstractOp { 
    | override def equals(other: Any) = other match { 
    |  case that: PushInt => this eq that 
    |  case _ => false 
    | } 
    | } 
defined class PushInt 

scala> val l = List(PushInt(1), PushInt(1), Pop(), Pop()) 
l: List[Product with AbstractOp] = List(PushInt(1), PushInt(1), Pop(), Pop()) 

scala> val op = l(1) 
op: Product with AbstractOp = PushInt(1) 

scala> println(l.indexOf(op)) 
1 

это, конечно, имею в виду PushInt(1) != PushInt(1), если это не тот же самый экземпляр PushInt(1). Не разорвать контракт equals/hashCode, потому что a.equals(b) => a.hashCode == b.hashCode, но a.hashCode == b.hashCode ничего не подразумевает.Но если ваша единственная польза найти этот экземпляр, попробуйте вместо этого:

scala> case class Pop() extends AbstractOp 
defined class Pop 

scala> case class PushInt(val i: Int) extends AbstractOp 
defined class PushInt 

scala> val l = List(PushInt(1), PushInt(1), Pop(), Pop()) 
l: List[Product with AbstractOp] = List(PushInt(1), PushInt(1), Pop(), Pop()) 

scala> val op = l(1) 
op: Product with AbstractOp = PushInt(1) 

scala> println(l.findIndexOf(op eq _)) 
1 

В любом случае, если вы переустановите этот экземпляр в списке, вы будете иметь проблемы. Вы должны убедиться, что каждый экземпляр, который вы вставляете, уникален. Вы можете даже написать свою собственную коллекцию, либо бросив исключение, если вставлен повторный экземпляр, либо сделайте копию любого переданного им экземпляра (достаточно просто с классами case и copy на Scala 2.8).

+0

Daniel, Что касается проблемы с отображением, если бы я использовал ваше второе предложение? Я думаю, что это не сработает, поэтому я должен, вероятно, переопределить равные права, верно? –

+0

Какая проблема с отображением? _ (читает Патрик) О, да. Да, есть. В этом случае вы можете переопределить 'equals' и создать альтернативный оператор сравнения для тех времен, в которые вы хотите« Push (1) == Push (1) ». Например, что-то вроде '= ~ ='. –

+0

Для первого решения обратите внимание на то, что вам не нужно проверять тип, указанный при проверке личности. Поэтому достаточно иметь: переопределить def равно (другое: любое) = этот eq другой – Blaisorblade

2

Если Йоа не против;) Представьте себе подобный код:

trait AbstractOp 
case class Pop() extends AbstractOp 
case class PushInt(val i:Int) extends AbstractOp 

теперь мы построим список, представляющий собой последовательность команд программы

val l=List(PushInt(1), PushInt(1), Pop(), Pop()) 

Первая проблема: вас хотите получить индекс операции

val op=l(1) // get the second operation for example 
// now you want to get back the index for the op you are using 
println(l.indexOf(op1)) // you will get 0 and not 1 

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

P.S. Конечно, это не ответ, я нашел, как убежищем `т отправить это под другие комментарии не стесняйтесь, чтобы переместить его в нужное место

+0

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

+0

Патрик объяснил требования очень хорошо. Спасибо! –

+0

Я перефразировал второй вопрос, чтобы упомянуть equals(). Вставка разных объектов с одним и тем же хэш-кодом в HahsMap - это только проблема с производительностью. – Blaisorblade

Смежные вопросы