我如何实现转型
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]
转到
[| 7; "text"; "lazytext" |]
这不起作用:
let createvalue<'t> (v: Object) : Object =
match v with
| :? Lazy<'t> as x -> x.Value :> Object
| x -> x
args |> Array.map createvalue
因为createvalue<'t>被编译器认为是createvalue<obj>
的,所以第一个模式大小写不匹配。
一种低效的解决方案是反射:
let createvalue (v: Object) : Object =
match v with
| _ when v.GetType().Name = "Lazy`1" ->
v.GetType().InvokeMember("Value", BindingFlags.GetProperty, null, v, [||])
| x -> x
但是有没有一种干净、直接的F#方法呢?
发布于 2021-06-02 06:05:45
我不认为使用异构的Lazy<'T>
元素可以很好地做到这一点,但是既然您无论如何都要丢弃类型信息,您会考虑让它们都变成Lazy<obj>
吗?如果是这样的话,解决方案是干净的:
let args : obj[] = [| lazy box 7; "text"; lazy box "lazytext" |]
let createvalue (v: obj) : obj =
match v with
| :? Lazy<obj> as x -> x.Value
| x -> x
发布于 2021-06-02 06:58:09
您不能这样做。
让我们来看看你使用的东西的类型:
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]
let createValue<'t> (v: obj) : obj = ...
module Array =
let inline map (mapping: 't -> 'u) (array:'t[]) = ...
因此,通过所有的泛型,乍一看,您试图做的事情似乎是正确的。但是如果仔细观察,就会发现在映射函数createValue<'t>(obj)
中,实际上是obj
,它在Array.map中用作't
类型。所以如果我们填入类型,你会得到这样的结果(并且使用这个createValue返回一个对象):
let args : Object[] = [| lazy 7; "text"; lazy "lazytext" |]
let createValue<'t> (v: obj) : obj =
match v with
| :? Lazy<'t> as x -> x.Value :> Object
| x -> x
module Array =
let inline map (mapping: obj -> obj) (array:obj[]) = ...
这表明,在本例中,Array.map只接受了来自obj -> obj
的函数。但是你的createValue<'otherT>(obj):obj
仍然是泛型的,所以F#会推断出obj的类型,因为你不需要对类型做任何事情,所以F#会推断出‘'otherT
’。因此,您传入的函数将类似于:
let createValue (v: obj) : obj =
match v with
| :? Lazy<obj> as x -> x.Value :> Object
| x -> x
您还可以传递createValue的其他具体版本。例如,如果你使用args |> Array.map createvalue<int>
,那么它将在所有的int实例上正常工作,但对于其他任何实例都不能。
如果你知道lazy可以包含的类型,你可以这样做:
let createvalue (v: obj) : obj =
match v with
| :? Lazy<int> as x -> x.Value :> obj
| :? Lazy<string> as x -> x.Value :> obj
| x -> x
但如果你不这样做,我担心你会陷入反思,或者像brianberns建议的那样改变你的方法。
发布于 2021-06-02 03:38:06
只需将createvalue
设置为内联函数,它就会工作。
https://stackoverflow.com/questions/67794942
复制相似问题