2015-04-27 14 views
5

Я читаю функциональное программирование в Scala, а в главе 04 авторы самостоятельно реализуют Option. Теперь, при определении функции getOrElse они используют верхнюю границу, чтобы ограничить тип A к надтипу (если правильно поняли)Scala Тип опции верхняя граница не понимает

Таким образом, определение гласит:

sealed trait Option[+A] { 
    def getOrElse[B >: A](default: => B): B = this match { 
    case None => default 
    case Some(a) => a 
    } 
} 

Так что, когда у нас есть что-то как

val a = Some(4) 
println(a.getOrElse(None)) => println prints a integer value 
val b = None 
println(b.getOrElse(Some(3)) => println prints a Option[Integer] value 

a имеет тип Option[Int], так A будет тип Int. B будет тип Nothing. Nothing - это подтип любого другого типа. Это означает, что Option[Nothing] является подтипом Option[Int] (из-за ковариации), правильно?

Но с B >: A мы сказали, что B должен быть супертипом ?! Итак, как мы можем вернуть Int? Это немного запутывает меня ...

Кто-нибудь хочет попробовать и уточнить?

ответ

8

Это означает, что Option [Nothing] является подтипом опции [Int] (из-за ковариации), правильно?

Исправить. Option[Nothing] - Option[Int].

Но с B>: A мы сказали, что B должен быть супертипом ?! Итак, как мы можем получить Int обратно?

Это не должно быть супертип. Он просто требует A как нижняя граница. Это означает, что вы все равно можете пройти Int до getOrElse, если A - Int.

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

class A 
class B extends A 
class C extends B 

scala> Option(new B) 
res196: Option[B] = Some([email protected]) 

scala> res196.getOrElse(new C) 
res197: B = [email protected] 

scala> res196.getOrElse(new A) 
res198: A = [email protected] 

scala> res196.getOrElse("...") 
res199: Object = [email protected] 

Я все еще могу передать экземпляр C, потому что C может быть до литого к B. Я также могу передать тип выше дерева наследования, а getOrElse вернет этот тип. Если я передаю тип, который не имеет ничего общего с типом, содержащимся в Option, тогда будет выведен тип с наименьшей верхней границей. В приведенном выше случае это Any.


Так почему же существует нижняя граница там вообще? Почему нет:

def getOrElse[B <: A](default: => B): B 

Это не будет работать, потому что getOrElse должен либо вернуть A, содержащуюся в Option, или по умолчанию B. Но если мы вернем A и A не является B, поэтому привязка типа недействительна.Возможно, если getOrElse вернулся A:

def getOrElse[B <: A](default: => B): A 

Это будет работать (если бы это было на самом деле определено, что путь), но вы были бы ограничены по типу-часам. Поэтому в приведенном выше примере вы можете пройти только B или C до getOrElse по адресу Option[B]. В любом случае, это не так, как в стандартной библиотеке.


Стандартная библиотека getOrElse позволяет передавать что-либо к нему. Скажем, у вас есть Option[A]. Если мы передадим подтип A, он будет добавлен к A. Если мы пройдем A, очевидно, это нормально. И если мы передадим какой-то другой тип, то компилятор отображает наименьшую верхнюю границу между ними. Во всех случаях выполняется привязка типа B >: A.

Потому что getOrElse позволяет вам что-либо передать, многие считают это очень сложным. Например, вы могли бы:

val number = "blah" 
// ... lots of code 
val result = Option(1).getOrElse(number) 

И это скомпилируется. У нас будет только Option[Any], который, вероятно, вызовет ошибку в другом месте.

+0

Спасибо, но не могли бы вы привести пример того, какой тип мы не смогли бы передать res196.getOrElse ... В настоящее время, с этим примером, я не вижу смысла иметь нижнюю границу. Или, лучше сказать, я теперь не понимаю, что это означает, что тип является нижней границей ... – Marin

+0

@Marin Вы можете передать любой тип 'getOrElse'. См. Мое редактирование. –

+0

спасибо! Кажется, я понял это сейчас. – Marin

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