1

我正在编写一个程序,在该程序中,我必须将一些 obj 类型的输入验证为数字类型。基本上,我正在寻找编写函数

validateint   : obj -> int option
validatefloat : obj -> float option
... and so on

这本身不是问题,例如,例如我得到了类似的东西:

let validateint x =
    match x with
        | y when y.GetType() = typeof<int>          -> y :?> int                 |> Some
        | y when y.GetType() = typeof<float>        -> y :?> float        |> int |> Some
        | y when y.GetType() = typeof<System.Int16> -> y :?> System.Int16 |> int |> Some
        /// ...more numeric cases
        | _                                         -> None

但是,在为 validateint 编写了类似的代码之后,我想考虑出一个将转换函数作为输入的函数,例如:

let validatenumeric cast x =
    match x with
        | y when y.GetType() = typeof<int>          -> y :?> int          |> cast |> Some
        | y when y.GetType() = typeof<float>        -> y :?> float        |> cast |> Some
        | y when y.GetType() = typeof<System.Int16> -> y :?> System.Int16 |> cast |> Some
        /// ...more numeric cases
        | _                                         -> None

然后定义

let validateint = validatenumeric int
let validatefloat = validatenumeric float
...

但是,这不起作用,因为 F# 基本上将强制转换的类型推断为 int -> 'a ,然后第二个和以后的匹配情况输入错误。我想我可以通过为每个数字类型添加一个额外的强制转换为浮点数来避免这种情况,但这感觉就像一个丑陋的黑客。有没有更优雅的解决方案?

4

3 回答 3

4

我认为您不需要自己重新实现该功能。.NET 中的System.Convert类型已经提供了一个尝试将任何输入转换为指定类型的操作,如果无法完成转换,则会失败。

let validateNumeric<'T> input =
  try Some(System.Convert.ChangeType(input, typeof<'T>) :?> 'T)
  with _ -> None

这是一个示例 F# Interactive 输出:

> validateNumeric<int> (box 1.1);;
val it : int option = Some 1
> validateNumeric<float> "1.1";;
val it : float option = Some 1.1
> validateNumeric<float> "xxx";;
val it : float option = None

不幸的是,没有一种方法不会抛出异常——因此,如果您需要转换数千个值,这对您来说可能太慢了。

于 2013-09-21T04:23:14.310 回答
2

您需要使用泛型类型,试试这个

let validate<'a, 'b> (cast: 'a -> 'b) (x: 'a) =
    try
        cast x |> Some
    with _ -> None

let a = validate int "123"
let b = validate int 1.23
let c = validate float "abc"
let d = validate<obj, decimal> Convert.ToDecimal (null :> obj)
let e = validate<string, DateTime> Convert.ToDateTime "2013-9-21"
于 2013-09-21T03:20:26.300 回答
0
open System
let validateint =function
  |(x:obj) when x=null->None
  | :? int as i->Some(i)
  | :? float as f->Some(f|>int)
  | :? string as s->Int32.TryParse(s)|>function |true,x->Some(x)|_->None
  //| :? ...
  |_->None
于 2013-09-21T10:00:47.500 回答