В чем разница между следующими операторами литья F #? Я не могу понять, почему и как все они разные.
(type) X
X :> type
X :?> type
В чем разница между следующими операторами литья F #? Я не могу понять, почему и как все они разные.
(type) X
X :> type
X :?> type
Первый не является отличным от F #, хотя, если вы привыкли к С#, может показаться, что он работает как один. Но на самом деле это вызывает функцию преобразования типов (например, int
), и скобки на самом деле не требуются (и, скорее всего, все это будет запутывать).
(int) "4" // the number 4 - this is a conversion, not a cast
int "4" // same thing, but idiomatic
int "NaN" // compiles but throws an exception at runtime
(int) (box 4) // doesn't compile because int doesn't do downcasts, just known conversions
Обратите внимание, что это работает для примитивных типов, поскольку существуют предопределенные функции преобразования, но это не будет работать для произвольных типов:
(bigint) 1 // no such conversion function, so this is a compile-time error
Различие между двумя другими заключается в том, что :>
выполняет upcasts (от типа к супертипу, который всегда безопасен), а :?>
выполняет downcasts (от типа к подтипу, который может завершиться неудачей, t25 > посередине).
Существуют также имена операторов upcast
и downcast
, которые можно использовать аналогичным образом:
5 :> obj // upcast int to obj
(upcast 5 : obj) // same
(box 5) :?> int // downcast an obj to int (successfully)
(downcast (box 5) : int) // same
(box "5") :?> int // downcast an obj to int (unsuccessfully)
В некоторых контекстах целевой тип upcast или downcast может быть успешно выведен, и в этом случае вам не нужны аннотации типа при использовании операторов upcast
или downcast
, тогда как вам всегда необходимо указать тип аргумент операторам :>
или :?>
(хотя вы можете предоставить _
, если вы ожидаете его вывода):
List.map (fun x -> x + 1) (downcast (box [1]))
List.map (fun x -> x + 1) (box [1] :?> _)