我有代码生成此警告。
有几则SO相关文章,最接近的是这一文章:这种结构导致代码的通用性低于类型注释所指示的通用性
但我看不到它的适用范围,因为我的代码已经在函数中
因此,所讨论的代码非常简单:
let exists (key: 'a) =
r.Exists(string key)
let set (key: 'a) value =
r.Set((string key), value)
let get (key: 'a) =
r.Get(string key)
let setDefault (key: 'a) value =
if not (exists key) then
set key value
我试图实现的目的是允许传递不同的枚举,字符串甚至是整数作为键,并且无论传递哪种类型,都将其转换为字符串(显然是在合理的范围内)
但是当我将该代码与枚举一起使用时,标题中会出现警告。
因此,我有两个问题:
您可以通过一个非常简单的测试用例来重现此警告,以消除示例中的一些干扰:
let f (x: 'a) =
string x
鉴于此,您可能会感到困惑,因为string
函数的类型是'T -> string
,但并不是那么简单。要了解正在发生的事情,您必须查看string
FSharp.Core中该函数的实现:
let inline anyToString nullStr x =
match box x with
| null -> nullStr
| :? System.IFormattable as f -> f.ToString(null,System.Globalization.CultureInfo.InvariantCulture)
| obj -> obj.ToString()
[<CompiledName("ToString")>]
let inline string (value: ^T) =
anyToString "" value
// since we have static optimization conditionals for ints below, we need to special-case Enums.
// This way we'll print their symbolic value, as opposed to their integral one (Eg., "A", rather than "1")
when ^T struct = anyToString "" value
when ^T : float = (# "" value : float #).ToString("g",CultureInfo.InvariantCulture)
when ^T : float32 = (# "" value : float32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int64 = (# "" value : int64 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int32 = (# "" value : int32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int16 = (# "" value : int16 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : nativeint = (# "" value : nativeint #).ToString()
when ^T : sbyte = (# "" value : sbyte #).ToString("g",CultureInfo.InvariantCulture)
when ^T : uint64 = (# "" value : uint64 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : uint32 = (# "" value : uint32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int16 = (# "" value : int16 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : unativeint = (# "" value : unativeint #).ToString()
when ^T : byte = (# "" value : byte #).ToString("g",CultureInfo.InvariantCulture)
这是使用静态解析的类型参数,并且为每个列出的类型使用显式实现,因此它实际上并不像从类型签名中看起来那样通用。在您的情况下,正在发生的事情是它推断出最兼容的类型,并且因为您的函数只是键入为'a
,所以它是picking obj
。因此,由于您正在调用string
并且您的输入参数被强制转换为string
函数实际处理的类型之一(实际上是in anyToString
),因此为obj
。
要使其在现实世界中的场景中工作实际上非常简单:只需使函数内联,根本不要在参数上放置类型:
let inline exists key =
r.Exists(string key)
这将推断出参数的类型并调用的正确版本string
,这几乎可以与您想要传递它的任何东西一起使用,包括枚举。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句