2009-11-15 1 views
6

мне нужно возвращать значения, и когда кто-то просит значение, сказать им, одна из трех вещей:Scala: Что-то вроде Option (Некоторые из них, None), но с тремя состояниями: Some, None, Неизвестных

  1. Здесь значение
  2. Там нет значения
  3. у нас нет никакой информации по этому значению (неизвестной)

корпус 2 тонко отличается от случая 3. Пример:

val radio = car.radioType 
  1. мы знаем значение: возвращает тип радио, скажем, «пионер»
  2. б. нет значения: return None
  3. c. нам не хватает данных об этом автомобиле, мы не знаем, есть ли у него радио или нет

Я думал, что могу расширить Scala's None и создать Неизвестный, но это не представляется возможным.

Предложения?

спасибо!

Update:

В идеале я хотел бы иметь возможность писать код так:

car.radioType match { 
    case Unknown => 
    case None => 
    case Some(radioType : RadioType) => 
} 

ответ

12

Вот скелетная реализация. Вы, наверное, хотите посмотреть на источнике для класса Option для некоторых наворотов:

package example 

object App extends Application { 
    val x: TriOption[String] = TriUnknown 

    x match { 
    case TriSome(s) => println("found: " + s) 
    case TriNone => println("none") 
    case TriUnknown => println("unknown") 
    } 
} 

sealed abstract class TriOption[+A] 
final case class TriSome[+A](x: A) extends TriOption[A] 
final case object TriNone extends TriOption[Nothing] 
final case object TriUnknown extends TriOption[Nothing] 
+0

Спасибо, это очень помогло. Я закончил реализацию чего-то подобного, с None и Some as sub-state of Known, через Option: http://code.alexblack.ca/an-option-class-in-scala-with-three-states-un –

2

Вы можете создать свой собственный с тремя возможностями. Или как один из ваших типов car.radioType, которые вы могли бы знать неизвестно, а затем используйте защитные приспособления на вашем футляре для его обработки. Если вы откатываете свой собственный, вы должны также включить свойство Product. liftweb имеет тип Box, который является опцией закрытия, которая позволяет полностью, пустым и erorr.

+0

Роллинг мой может работать - мне нужно, чтобы он использовался для многих типов ценностей, а не только для car.radioType. Я посмотрел на коробку Лифт, и мне кажется, что она поддерживает только две ценности (Полная, Пусто): http://scala-tools.org/scaladocs/liftweb/1.0/net/liftweb/util/Box.html –

+0

I думайте, что вы смотрите на это неправильно. У вас есть метод, который возвращает Box. Коробка может быть одним из трех унаследованных классов: «Полный», «Сбой» или «Пусто». , если вы следуете опциям и/или коробке в качестве шаблона, вы также можете использовать flatMap, map или forEach. Затем вы можете использовать оператор соответствия, чтобы определить, какое значение оно есть. –

+0

А, я понимаю, что вы имеете в виду сейчас о Боксе. –

4

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

scala> type Result = Either[String, Option[String]] 
defined type alias Result 

scala> val hasValue: Result = Right(Some("pioneer")) 
hasValue: Result = Right(Some(pioneer)) 

scala> val noValue: Result = Right(None) 
noValue: Result = Right(None) 

scala> val unknownValue = Left("unknown") 
unknownValue: Left[java.lang.String,Nothing] = Left(unknown) 
+1

Это хорошая идея, но кажется немного многословной. В идеале я бы хотел написать такой код: car.radioType match {case Unknown => case None => case Some (radioType: RadioType) =>} –

5

Вы можете захватить некоторые вещи из Lift: Коробка. Он имеет три состояния: «Полный», «Сбой» и «Пусто». Кроме того, Empty и Failure наследуются от EmptyBox.

8

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

car.radioType match { 
    case null => 
    case None => 
    case Some(radioType : RadioType) => 
} 
+1

Это звучит просто, но кощунственно :) –

0

я сделал что-то вроде похож классифицировать 3 типа линий в данном файле, данная линия может быть, например, Float для строки заголовка, Long для строки в (строке) среднего или String для тягач. Также isHeader, isRow и isTrailer могут быть использованы, чтобы узнать, какой из них.Надеюсь, помогает:

sealed abstract class HRT[+H, +R, +T] { 
    val isHeader: Boolean 
    val isRow: Boolean 
    val isTrailer: Boolean 
} 

final case class Header[+H, +R, +T](h: H) extends HRT[H, R, T] { 
    override val isHeader: Boolean = true 
    override val isRow: Boolean = false 
    override val isTrailer: Boolean = false 
} 

final case class Row[+H, +R, +T](r: R) extends HRT[H, R, T] { 
    override val isHeader: Boolean = false 
    override val isRow: Boolean = true 
    override val isTrailer: Boolean = false 
} 

final case class Trailer[+H, +R, +T](t: T) extends HRT[H, R, T] { 
    override val isHeader: Boolean = false 
    override val isRow: Boolean = false 
    override val isTrailer: Boolean = true 
} 

object Demo { 
    def getEntries(): Seq[HRT[Float, Long, String]] = 
    List(
     Header(3.14f), 
     Row(42), 
     Trailer("good bye") 
    ) 

    val entries = getEntries() 

    entries.foreach { 
    case Header(f) => printf("header: %f\n", f) 
    case Row(l) => printf("row: %d\n", l) 
    case Trailer(s) => printf("trailer: %s\n", s) 
    } 
}