即使传递了非null参数,函数参数也为null [英] Function argument is null, even though a non-null argument is passed
问题描述
这里是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
模块中的许多功能已经为您完成了,而您不需要不需要接受元组,然后使用tFst
,tSnd
和tTrd
对其进行解构,编译器可以为您完成:
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屋!