f#模式匹配顺序:?seq< _>(IEnumerable) [英] f# pattern matching sequence :? seq<_> (IEnumerable)

查看:50
本文介绍了f#模式匹配顺序:?seq< _>(IEnumerable)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将结果发送到将内容输出到控制台/日志的单个方法

I want to send a result to a single method that outputs the content to the Console/Log

我曾希望检测结果是否包含IEnumerable并遍历该集合以获取结果.

I had hoped to detect whether the result contained an IEnumerable and traverse that collection for its results.

这无法识别seq,只是将其识别为 Other Object .

This fails to recognize a seq and simply identifies it as Other Object.

很抱歉.

let rec LogResultGeneric (logInfo: string -> unit, logError: string -> unit) (result: Result<_, _>) =
    let innerSelect (item: _) =
        match item |> box with
        | :? Result<_, _> as res ->
            "RESULT" |> logInfo
            res |> LogResultGeneric(logInfo, logError)
        | _ ->
            "VALUE" |> logInfo
            item |> LogValueGeneric logInfo

    "DISPLAY OUTCOME : " + result.ToString() |> logInfo 
    match result with
    | Error msg ->
        "ERROR RESULT" |> logError
        match msg |> box with
        | :? string as msg -> msg |> logError
        | _ -> msg.ToString() |> logError

    | Ok payload ->
        "OK RESULT" |> logInfo

        match payload |> box with
        | :? seq<obj> as s ->
            "IENUMERABLE" |> logInfo
            s
            |> Seq.iter innerSelect
        | _ ->
            "VALUE" |> logInfo
            payload |> LogValueGeneric logInfo
        |> ignore

推荐答案

将值与泛型类型匹配的模式很棘手-因为编译器无法静态地知道中的'a seq<'a> 应该是.针对 seq< obj> 的模式匹配也不起作用,因为例如 seq< int> 不实现 seq< obj> .

Pattern matching a value against a generic type is tricky - because the compiler does not statically know what the 'a in seq<'a> should be. Pattern matching against seq<obj> also does not work, because e.g. seq<int> does not implement seq<obj>.

但是,对于集合来说,您很幸运,因为通用的 IEnumerable<'T> 继承自非通用的 IEnumerable ,因此您可以使用它:

However, for collections, you are lucky because a generic IEnumerable<'T> inherits from non-generic IEnumerable and so you can use that:

let print payload = 
  match box payload with 
  | :? System.Collections.IEnumerable as ie ->
      let en = ie.GetEnumerator()
      while en.MoveNext() do
        printfn "ITEM: %A" en.Current
  | v -> 
      printfn "VALUE: %A" v

print [1;2;3]
print "ABC"

要使像这样的东西适用于没有非通用基本类型的通用类型,例如 option<'T> ,难度会更大,通常需要反思.

Getting something like this to work for generic types that do not have a non-generic base type such as option<'T> is harder and generally requires reflection.

一个技巧是拥有一个通用的帮助器类,并使用反射将其专门化为正确的类型,然后调用该方法(但通常这很丑陋):

One trick is to have a generic helper class and use reflection to specialize that to the right type and then invoke the method (but generally, this is pretty ugly):

type OptionPrinter<'T> = 
  static member Print(o:option<'T>) = 
    match o with 
    | None -> printfn "Nothing"
    | Some v -> printfn "Something: %A" v 

let print payload = 
  match box payload with 
  | :? System.Collections.IEnumerable as ie ->
      let en = ie.GetEnumerator()
      while en.MoveNext() do
        printfn "ITEM: %A" en.Current
  | null -> 
      printfn "NULL (or None)"
  | v when v.GetType().IsGenericType && 
          v.GetType().GetGenericTypeDefinition() = typedefof<option<_>> ->
      let tya = v.GetType().GetGenericArguments()
      let ty = typedefof<OptionPrinter<_>>.MakeGenericType(tya)
      ty.GetMethod("Print").Invoke(null, [| v |]) |> ignore
  | v -> 
      printfn "VALUE: %A" v

print [1;2;3]
print "ABC"
print (Some 10)
print None

这篇关于f#模式匹配顺序:?seq&lt; _&gt;(IEnumerable)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆