即使传递了非null参数,函数参数也为null [英] Function argument is null, even though a non-null argument is passed

查看:90
本文介绍了即使传递了非null参数,函数参数也为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是F#新手,对不起,标题不好,我不知道该怎么形容.
我遇到的非常奇怪的问题.这是相关的代码段:

F# newbie here, and sorry for the bad title, I'm not sure how else to describe it.
Very strange problem I'm having. Here's the relevant code snippet:

let calcRelTime (item :(string * string * string)) =
     tSnd item
     |>DateTime.Parse
     |> fun x -> DateTime.Now - x
     |> fun y -> (floor y.TotalMinutes).ToString()
     |>makeTriple (tFst item) (tTrd item) //makeTriple switches y & z. How do I avoid having to do that? 


let rec getRelativeTime f (l :(string * string * string) list) = 
    match l with
    | [] -> f
    | x :: xs -> getRelativeTime (List.append [calcRelTime x] f) xs

我使用Visual Studio逐步进行了调试,它清楚地表明getRelativeTime中的 x 是一个三元组,具有格式正确的日期时间字符串.但是当我进入calcRelTime item 时为null.一切最终返回一个具有原始日期时间字符串的三元组,而不是具有过去总分钟数的三元组.在该日期时间字符串命中一个期望它是整数字符串的函数之前,任何地方都没有其他错误.

I step through it with Visual Studio and it clearly shows that x in getRelativeTime is a 3-tuple with a well-formed datetime string. But when I step to calcRelTime item is null. Everything ends up returning a 3-tuple that has the original datetime string, instead of one with the total minutes past. There's no other errors anywhere, until the that datetime string hits a function that expects it to be an integer string.

任何帮助将不胜感激! (以及其他有关这些功能的F#样式提示/建议).

Any help would be appreciated! (along with any other F# style tips/suggestions for these functions).

推荐答案

item为空,因为尚未从其各个部分构造它. F#编译器将元组参数编译为单独的实际(IL级)参数,而不是类型为Tuple<...>的一个参数.如果您在ILSpy中查看编译后的代码,则会看到此签名(使用C#语法):

item is null, because it hasn't been constructed yet out of its parts. The F# compiler compiles tupled parameters as separate actual (IL-level) parameters rather than one parameter of type Tuple<...>. If you look at your compiled code in ILSpy, you will see this signature (using C# syntax):

public static Tuple<string, string, string> calcRelTime(string item_0, string item_1, string item_2)

这样做有几个原因,包括与其他CLR语言的互操作性以及效率.

This is done for several reasons, including interoperability with other CLR languages as well as efficiency.

可以肯定的是,元组本身是根据这些参数构造的(除非您已打开优化功能),但不是马上创建的.如果迈出一步(按F11键),item将获得适当的非null值.

To be sure, the tuple itself is then constructed from these arguments (unless you have optimization turned on), but not right away. If you make one step (hit F11), item will obtain a proper non-null value.

如果您在Visual Studio中转到调试"->"Windows"->本地",则还可以看到这些编译器生成的参数.

You can also see these compiler-generated parameters if you go to Debug -> Windows -> Locals in Visual Studio.

至于为什么它返回原始列表而不是修改后的列表,我真的不能说:在我的设置中,一切都按预期工作:

As for why it's returning the original list instead of modified one, I can't really say: on my setup, everything works as expected:

> getRelativeTime [] [("x","05/01/2015","y")]
val it : (string * string * string) list = [("x", "y", "17305")]

也许您分享您的测试代码,我就能告诉您更多信息.

Perhaps if you share your test code, I would be able to tell more.

最后,您可以做的事情更简单:您无需自己编写递归循环,List模块中的许多功能已经为您完成了,而您不需要不需要接受元组,然后使用tFsttSndtTrd对其进行解构,编译器可以为您完成:

And finally, what you're doing can be done a lot simpler: you don't need to write a recursive loop yourself, it's already done for you in the many functions in the List module, and you don't need to accept a tuple and then deconstruct it using tFst, tSnd, and tTrd, the compiler can do it for you:

let getRelativeTime lst = 
   let calcRelTime (x, time, y) =
      let parsed = DateTime.Parse time
      let since = DateTime.Now - parsed
      let asStr = (floor since.TotalMinutes).ToString()
      (x, asStr, y)
   List.map calRelTime lst

这篇关于即使传递了非null参数,函数参数也为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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