Как смоделировать безопасные с точки зрения типов перечислимые типы?

В случае, если Вы - программист .NET: VS 2008 имеет довольно большую поддержку JS включая intellisense на динамично добавленных методах/свойствах и удобный отладка .

311
задан Jacek Laskowski 22 January 2015 в 13:03
поделиться

4 ответа

http://www.scala-lang.org/docu/files/api/scala/Enumeration.html

Example use

  object Main extends App {

    object WeekDay extends Enumeration {
      type WeekDay = Value
      val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
    }
    import WeekDay._

    def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)

    WeekDay.values filter isWorkingDay foreach println
  }
187
ответ дан 23 November 2019 в 01:12
поделиться

Есть много способов сделать это.

1) Используйте символы. Однако это не даст вам никакой безопасности типов, кроме того, что вы не примете несимволы там, где ожидается символ. Я упоминаю об этом здесь только для полноты картины. Вот пример использования:

def update(what: Symbol, where: Int, newValue: Array[Int]): MatrixInt =
  what match {
    case 'row => replaceRow(where, newValue)
    case 'col | 'column => replaceCol(where, newValue)
    case _ => throw new IllegalArgumentException
  }

// At REPL:   
scala> val a = unitMatrixInt(3)
a: teste7.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 0 1 /

scala> a('row, 1) = a.row(0)
res41: teste7.MatrixInt =
/ 1 0 0 \
| 1 0 0 |
\ 0 0 1 /

scala> a('column, 2) = a.row(0)
res42: teste7.MatrixInt =
/ 1 0 1 \
| 0 1 0 |
\ 0 0 0 /

2) Использование класса Enumeration :

object Dimension extends Enumeration {
  type Dimension = Value
  val Row, Column = Value
}

или, если вам нужно сериализовать или отобразить его:

object Dimension extends Enumeration("Row", "Column") {
  type Dimension = Value
  val Row, Column = Value
}

Это можно использовать следующим образом:

def update(what: Dimension, where: Int, newValue: Array[Int]): MatrixInt =
  what match {
    case Row => replaceRow(where, newValue)
    case Column => replaceCol(where, newValue)
  }

// At REPL:
scala> a(Row, 2) = a.row(1)
<console>:13: error: not found: value Row
       a(Row, 2) = a.row(1)
         ^

scala> a(Dimension.Row, 2) = a.row(1)
res1: teste.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 1 0 /

scala> import Dimension._
import Dimension._

scala> a(Row, 2) = a.row(1)
res2: teste.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 1 0 /

К сожалению, это не гарантирует, что все совпадения учтены. Если бы я забыл указать строку или столбец в совпадении, компилятор Scala не предупредил бы меня. Таким образом, это дает мне некоторую безопасность типов, но не столько, сколько можно получить.

3) Объекты случая:

sealed abstract class Dimension
case object Row extends Dimension
case object Column extends Dimension

Теперь, если я оставлю регистр при совпадении ], компилятор предупредит меня:

MatrixInt.scala:70: warning: match is not exhaustive!
missing combination         Column

    what match {
    ^
one warning found

Он используется примерно так же, и даже не требует import :

scala> val a = unitMatrixInt(3)
a: teste3.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 0 1 /

scala> a(Row,2) = a.row(0)
res15: teste3.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 1 0 0 /

Тогда вы можете спросить, зачем вообще использовать Enumeration вместо дело объекты. На самом деле, case-объекты действительно имеют много преимуществ, например, здесь. Однако класс Enumeration имеет много методов Collection, таких как элементы (итератор в Scala 2.8), которые возвращают Iterator, map, flatMap, filter и т. Д.

98
ответ дан 23 November 2019 в 01:12
поделиться

Немного менее подробный способ объявления именованных перечислений:

object WeekDay extends Enumeration("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat") {
  type WeekDay = Value
  val Sun, Mon, Tue, Wed, Thu, Fri, Sat = Value
}

WeekDay.valueOf("Wed") // returns Some(Wed)
WeekDay.Fri.toString   // returns Fri

Конечно, проблема здесь в том, что вам понадобится чтобы синхронизировать порядок имен и vals, что проще сделать, если name и val объявлены в одной строке.

52
ответ дан 23 November 2019 в 01:12
поделиться

Я должен сказать, что пример скопирован из документации Scala , написанной skaffman выше, имеет ограниченную полезность на практике (вы также можете использовать case object s).

Чтобы получить что-то наиболее близкое, напоминает Java Enum (т.е. с разумными методами toString и valueOf - возможно, вы сохраняете значения перечисления в базе данных) вам нужно немного изменить его. Если вы использовали код skaffman :

WeekDay.valueOf("Sun") //returns None
WeekDay.Tue.toString   //returns Weekday(2)

Тогда как при использовании следующего объявления:

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon = Value("Mon")
  val Tue = Value("Tue") 
  ... etc
}

вы получите более разумные результаты:

WeekDay.valueOf("Sun") //returns Some(Sun)
WeekDay.Tue.toString   //returns Tue
376
ответ дан 23 November 2019 в 01:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: