[英]Why can't F# infer the type in this case?
考虑以下示例代码,其中我有一个泛型类型和2个静态成员构造函数,它们创建所述类型的专用实例。
type Cell<'T> = { slot: 'T }
with
static member CreateInt x : IntCell = { slot = x }
static member CreateString x : StringCell = { slot = x}
and IntCell = Cell<int>
and StringCell = Cell<string>
// Warnings on the next 2 lines
let x = Cell.CreateInt 123
let y = Cell.CreateString "testing"
我认为我有必要的类型注释,但F#给了我警告。 例如:
Warning 2 The instantiation of the generic type 'Cell' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, eg 'Cell<_>'.
如何让警告消失?
正如@ildjarn暗示的那样, Cell
是一个泛型类型,编译器想要在调用静态成员时知道类型'T
// Two ways to fix the compiler warning
let x = Cell<int>.CreateInt 123
let y = StringCell.CreateString "testing"
避免指定'T
是将创建函数移动到模块中。
type Cell<'T> = { slot: 'T }
type IntCell = Cell<int>
type StringCell = Cell<string>
module Cell =
let createInt x : IntCell = { slot = x }
let createString x : StringCell = { slot = x }
let x = Cell.createInt 123
let y = Cell.createString "testing"
但是,由于您无论如何都要在函数名中指定所需的类型,因此可能首选以下语法。
type Cell<'T> = { slot: 'T }
with
static member Create (x : 'T) = { slot = x }
type IntCell = Cell<int>
type StringCell = Cell<string>
let x = IntCell.Create 123
let y = StringCell.Create "testing"
// or simply
let z = Cell<float>.Create 1.0
感谢@Vandroiy指出我的Create
方法中缺少的类型约束,以及他的答案,该答案显示了编译器如何通过调用静态方法确定通用类型Cell
'T
值。
编译器无法确定方法CreateInt
和CreateFloat
的泛型参数'T
,因为它与方法的返回类型无关。 在这个问题中,写下来是有效的:
Cell<float>.Create 1.0 // useless type annotation to remove warning
但是,你也可以写
Cell<string>.Create 1.0 // Trollolol
为避免这种情况,您需要确保工厂只能生成它所调用的类型。 在泛型类型上声明工厂时,使用类型注释将其返回类型的泛型参数与其调用类型的泛型参数等同。
在我看来,复杂的表述增加了混乱。 你可以达到预期的效果
type Cell<'T> =
{ slot: 'T }
static member Create (x : 'T) = { slot = x }
let x = Cell.Create 123
let y = Cell.Create "testing"
请注意x
的类型注释,它将工厂的输入类型与Cell<>
类型的泛型参数等同起来!
编辑发表评论:
按IntCell
, StringCell
和StringCell
类型没有用处; 它们只是Cell<int>
和Cell<string>
一种不太可读的形式。 从评论到这个答案,我理解应该暴露这些类型而不是Cell
。 据我所知,如果在问题中定义它们是不可能的,因为类型缩写最多具有它们缩写的类型的可访问性。
这是一个合理的设计选择:如果类型是通用的,它应该接受所有有效的泛型类型参数。 如果IntCell
和StringCell
添加了专门的实现,通常的方法是组合它们适当的Cell类型实例化及其专用功能。 然后,允许Cell类型具有比专用类型更受限制的可访问性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.