实现具有带泛型类型参数的方法的F#接口类型
f#
在F# 组件设计指南的使用接口对相关操作进行分组部分中,它列出了此接口类型,该接口类型具有带有泛型类型参数'T.
type Serializer =
abstract Serialize<'T> : preserveRefEq: bool -> value: 'T -> string
abstract Deserialize<'T> : preserveRefEq: bool -> pickle: string -> 'T
该对象的表达式引用部分和接口的参考部分没有列出如何实现一个通用的接口,任何实例'T参数。该泛型参考部分确实有在本节的最后一个简单的例子......我仍然有困难,编写代码,反映那个例子。
我知道如何实现具有泛型类型的接口,而不是具有泛型类型参数的接口。
这是我一直试图实现的一个简单的玩具示例,以了解如何执行此操作:
type Foo = Foo of string
type Bar = Bar of string
let unwrapFoo (Foo foo) = foo
let unwrapBar (Bar bar) = bar
type IWrapper =
abstract member Unwrap<'T> : 'T -> string
abstract member Wrap<'U> : string -> 'U
试图实现IWrapper是我遇到编译器错误的地方:
let wrapper =
{ new IWrapper with
member this.Unwrap<Foo>(foo: Foo) = unwrapFoo foo
member this.Wrap<Bar> string = Bar string }
该wrapper让利结合会给我回一个编译器错误:Unexpected identifier in pattern. Expected infix operator, quote symbol or other token.
我实现的其他尝试IWrapper给了我这个编译器错误:typecheck error The member 'Unwrap<'T> : Foo -> string' does not have the correct type to override the corresponding abstract method. The required signature is 'Unwrap<'T> : 'T -> string'.
let wrapper =
{ new IWrapper with
member this.Unwrap<'T>(foo: Foo) = unwrapFoo foo
member this.Wrap<'U> string = Bar(string) }
非常感谢实现此接口类型的任何帮助以及对阅读编译器错误消息的洞察(我确信这是向我解释如何解决我的问题)。谢谢窥视!
回答
通用签名并不意味着你认为它意味着什么。
这并不意味着“我将采用某种类型作为参数。还不知道该类型是什么,我稍后再决定,但现在让我们称之为'T”。这不是它的意思。
相反,它的意思是“选择一种类型,任何类型。我不知道你要选择什么,所以现在让我们称之为'T。选择类型了吗?很好!现在我将采用该类型的参数”
换句话说,选择类型参数的是函数的调用者,而不是实现者。
与其他通用函数进行比较。让我们List.length举个例子。它具有以下签名:
List.length<'a> : 'a list -> int
这个签名说:“选择任何类型'a。任何类型,我不在乎哪个。然后我会拿一个类型列表'a list并返回给你一个int”
它的实现者不能随意决定将某些特定列表作为参数 - 例如int list, - 不,他们必须以适用于任何类型的方式编写函数。因为这就是类型签名所承诺的。
这意味着,如果您IWrapper按照定义的方式定义了接口,则方法必须能够接受任何类型,而不仅仅是Foo和Bar。因为这就是方法的类型签名所承诺的。
但在我看来,您真正想做的是创建一个特定于类型的包装器。一个包装器,可以包装和解开某些特定的两种类型,而不仅仅是一般的任何类型。是这样吗?
如果是这种情况,那么类型参数应该在接口上,而不是在方法上:
type IWrapper<'T, 'U> =
abstract member Unwrap : 'T -> string
abstract member Wrap : string -> 'U
此定义表示“如果您有自己的 实例IWrapper<a, b>,那么您可以使用它来解a包或换行b,仅此而已”
现在您可以专门为Fooand创建一个包装器Bar:
let foobarWrapper =
{ new IWrapper<Foo, Bar> with
member this.Unwrap foo = unwrapFoo foo
member this.Wrap string = Bar string }