Несмотря на то, что isNull
- очень простой ответ, он вполне оправдан, я подумал, что было бы интересно поиграть с несколькими другими, потому что F # - это весело :)
Сначала давайте настроим небольшую функцию для быстрого тестирования результатов
open System
let test f a =
try
printfn "Input %A, output %A" a (f a)
printfn "Input %A, output %A" "" (f "")
printfn "Input %A, output %A" null (f null)
with
| :? Exception as ex -> printfn "%s" ex.Message
Наша первая функция - просто установить базовый уровень.
Выдает исключение
//string -> string
let getLast1 ( s:string) : string = s.[s.Length-1] |> string
printfn "=== getLast1 ==="
test getLast1 "bing"
=== getLast1 ===
Вход «bing», выход «g»
Индекс находился за пределами массива.
Следующий проверяет значение с помощью if
и возвращает пустую строку, если не является допустимым значением.
Возвращает пустую строку
//string -> string
let getLast2 ( s:string) : string =
if (String.IsNullOrEmpty s) then ""
else s.[s.Length-1] |> string
printfn "=== getLast2 ==="
test getLast2 "bing"
=== getLast2 ===
Вход «bing», выход «g»
Вход "", выход ""
Вход, выход ""
По крайней мере, сейчас выполняются все пути.
Давайте попробуем более функциональный подход:
Возвращает option
с использованием сопоставления с шаблоном
//string -> string option
let getLast3 (s:string) =
match s with
| null -> None
| _ ->
match (s.ToCharArray()) with
| [||] -> None
| [|x|] -> Some x
| xs -> Array.tryLast xs
|> Option.map string
printfn "=== getLast3 ==="
test getLast3 "bing"
=== getLast3 ===
Вход "Бинг", вывод Некоторые "г"
Ввод "", вывод // обратите внимание, что на самом деле None
здесь.
Ввод , вывод // обратите внимание, что здесь None
.
Это работает, но это не самая простая функция для чтения. Это не так уж плохо, но что, если мы попытаемся сломать это.
Составная функция
//'a -> 'a option
let sanitize x = if (isNull x) then None else Some(x)
//string -> char[]
let toCharArray (s:string) = s.ToCharArray()
//'a[] option -> 'a option
let last xs =
xs |> Option.map Array.tryLast //tryLast returns an 'a option
|> Option.flatten // turns 'a option option to a' option
Теперь, когда у нас есть строительные блоки, мы можем создать нашу новую последнюю функцию:
//string -> string option
let getLast4 s =
s |> sanitize
|> Option.map toCharArray
|> last
|> Option.map string
printfn "=== getLast4 ==="
test getLast4 "bing"
=== getLast4 ===
Вход "bing", вывод Some "g"
Ввод "", вывод // обратите внимание, что здесь на самом деле None
.
Ввод, вывод // обратите внимание, что на самом деле None
здесь.
Если честно, getLast2
, наверное, хорошо. Если бы я обнаружил, что проверяю пустую строку, я бы предпочел вернуть Some
или None
из if
. Я просто хотел показать, как отойти от null
и использовать встроенные функции Array
.