在ToString()vs字符串运算符

时间:2016-12-28 23:34:41

标签: generics f# type-inference

注意:这个问题与我的previous one有些相关,但实际上从不同的角度来看这个问题

请考虑以下代码段:

let toStr a = a.ToString()
let strOp a = string a

let intToStr = 5 |> toStr
let floatToStr = 5.0 |> toStr

let intStrOp = 5 |> strOp
let floatStrOp = 5.0 |> strOp //type inference error

虽然strOp函数使用看起来更优雅的解决方案,并且能够将单位值转换为字符串,但它似乎不是真正的通用,因为它的类型受到限制它的第一次使用(甚至推断的类型是obj -> string,而不是'a -> string

为什么字符串运算符不能以这种通用方式工作?或者我做错了什么?

1 个答案:

答案 0 :(得分:4)

不同之处在于string使用静态成员约束(请参阅the definition),而ToString是任何对象上可用的普通方法,因此编译器会处理ToString调用作为通用代码,不以任何方式约束实例类型。

静态约束和(非静态)泛型在(无约束)let绑定函数中使用时以不同方式工作:

  • 对于通用代码,编译器传播通用性并使您编写的let绑定函数也是通用的。

  • 对于静态成员约束,编译器根据第一次使用来专门化代码。正如评论中所提到的,您可以通过使用inline来避免这种情况,string允许基于静态成员的通用性以与序数通用代码相同的方式传播。

我认为ToString函数使用静态解析类型约束的唯一原因是它允许它专门用作原始类型的普通null调用,但仍处理toStr null值对象的自定义方式 - strOp null抛出异常但{{1}}返回空字符串!