Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Заметка гибкого типа указывает, что параметр, переменная или значение имеет тип, совместимый с указанным типом, где совместимость определяется позицией в объектно-ориентированной иерархии классов или интерфейсов. Гибкие типы полезны, особенно если автоматическое преобразование в типы выше в иерархии типов не происходит, но вы по-прежнему хотите включить функциональность для работы с любым типом в иерархии или любым типом, реализующим интерфейс.
Синтаксис
#type
Замечания
В предыдущем синтаксисе тип представляет базовый тип или интерфейс.
Гибкий тип эквивалентен универсальному типу, который имеет ограничение, которое ограничивает допустимые типы типами, совместимыми с базовым или типом интерфейса. То есть следующие две строки кода эквивалентны.
#SomeType
'T when 'T :> SomeType
Гибкие типы полезны в нескольких типах ситуаций. Например, если у вас есть функция с более высоким порядком (функция, которая принимает функцию в качестве аргумента), функция часто полезно возвращать гибкий тип. В следующем примере использование гибкого типа с аргументом iterate2 последовательности позволяет функции более высокого порядка работать с функциями, которые создают последовательности, массивы, списки и любой другой перечислимый тип.
Рассмотрим следующие две функции, одна из которых возвращает последовательность, другая из которых возвращает гибкий тип.
let iterate1 (f : unit -> seq<int>) =
for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
for e in f() do printfn "%d" e
// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)
// Passing a function that takes a list to the version that specifies a
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])
В качестве другого примера рассмотрим функцию библиотеки Seq.concat :
val concat: sequences:seq<#seq<'T>> -> seq<'T>
В эту функцию можно передать любую из следующих перечисленных последовательностей:
- Список списков
- Список массивов
- Массив списков
- Массив последовательностей
- Любое другое сочетание перечисленных последовательностей
Следующий код используется Seq.concat для демонстрации сценариев, которые можно поддерживать с помощью гибких типов.
let list1 = [1;2;3]
let list2 = [4;5;6]
let list3 = [7;8;9]
let concat1 = Seq.concat [ list1; list2; list3]
printfn "%A" concat1
let array1 = [|1;2;3|]
let array2 = [|4;5;6|]
let array3 = [|7;8;9|]
let concat2 = Seq.concat [ array1; array2; array3 ]
printfn "%A" concat2
let concat3 = Seq.concat [| list1; list2; list3 |]
printfn "%A" concat3
let concat4 = Seq.concat [| array1; array2; array3 |]
printfn "%A" concat4
let seq1 = { 1 .. 3 }
let seq2 = { 4 .. 6 }
let seq3 = { 7 .. 9 }
let concat5 = Seq.concat [| seq1; seq2; seq3 |]
printfn "%A" concat5
Выходные данные выглядят следующим образом.
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
В F#, как и в других объектно-ориентированных языках, существуют контексты, в которых производные типы или типы, реализующие интерфейсы, автоматически преобразуются в базовый тип или тип интерфейса. Эти автоматические преобразования происходят в прямых аргументах, но не в том случае, если тип находится в подчиненном положении, в составе более сложного типа, например возвращаемого типа типа функции или в качестве аргумента типа. Таким образом, нотация гибкого типа в первую очередь полезна при применении типа к нему является частью более сложного типа.