Нижняя граница типа T
всегда будет выведена. Если явно не задана нижняя граница типа, ничто не является границей.
Этот вывод является правильным. Поскольку общий тип параметра стирается во время выполнения, вызовы f[String]("foo")
, f[File]("foo")
и f[List[Int]]("foo")
и f[Nothing]("foo")
- это один и тот же вызов f("foo")
во время выполнения. Результат должен быть действительным String
, File
, List[Int]
и Nothing
. Быть Nothing
- единственный способ удовлетворить это (что означает, что результата не будет). Если бы была более сильная нижняя граница типа, она должна была бы быть только этого типа.
Следствием этого является то, что подпрограмма f[T >: LowerBound](parameters): T,
, где T
не появляется в parameters
, ничем не отличается от f(parameters): LowerBound
, и нет смысла делать ее родовой (когда LowerBound
не указано явно, граница типа Nothing
)
С той же идеей, что вызов f[T]("foo")
только f("foo")
во время выполнения, ясно, что имя не может появиться в сообщении об исключении. Таким образом, T
должен быть каким-то образом пропущен во время выполнения, и манифесты являются обычным способом сделать это, как отметил Дейв. Теперь T
появляется в параметрах, и все по-другому. если кто-то вызывает f[File]("foo")
, компилятор преобразует это в f("foo")(manifest_of_file)
, где manifest_of_file
позволяет, среди прочего, получить имя типа File.
Это все еще не вывод, поскольку File
было написано явно. Единственный способ определить тип T
- это от ожидаемого типа вызова к f
в контексте. Если кто-то делает val file: File = f("foo")
или передает f("foo")
значение параметра типа File в какую-либо подпрограмму или просто пишет f("foo"): File
, будет ли File
выводиться? Нет не будет Еще раз, Nothing
будет выведено. Причина в том, что это более точный тип, чем File, и поскольку компилятор может передавать либо Manifest [File], либо Manifest [Nothing] (и любой другой тип между ними), он выбирает более точный. Это может быть удивительно для Nothing
, но предположим, что ваша нижняя граница типа String
, а ожидаемый тип просто AnyRef
, нет очевидной причины выбирать AnyRef, а не более String.
def f[T >: String : Manifest](s: String): T = "type is " + manifest[T].toString
val x: AnyRef = f("foo"): AnyRef
x: Anyref = type is java.lang.String
То же самое с вашим примером и Nothing
как нижняя граница типа:
def g[T: Manifest](s: String): T = throw new Exception("type is " + manifest[T])
val y: String = g("foo"): String
java.lang.Exception: type is Nothing
at .g(<console>:7)
....