F#泛型类型约束和鸭子打字 [英] F# generic type constraints and duck typing
问题描述
我想实现F#鸭打字,我发现,你可以有一个的 F#泛型中的成员约束如下:
type ListEntryViewModel <'T当'T:(member Name :string)>(model:'T)=
inherit ViewModelBase()
成员this.Name with get()= model.Name
但是,当我尝试引用该属性时,上述代码不会编译。我收到一个编译器错误:
这段代码不够通用。当^ T
:(成员get_Name:^ T - >字符串)时,类型变量^ T不能一概而论,因为
会跳过它的作用域。
是否可以通过泛型约束实现鸭子打字?
最近其中构件约束了在类型声明使用了类似的问题。
我不确定如何纠正样本以使其可以编译,但如果这不可能,我不会感到惊讶。成员约束被设计为与静态解析的类型参数一起使用,特别是与 inline
函数或成员一起使用,并且我不认为它是惯用的F#代码,可以将它们与类型参数
我认为对您的示例更习惯的解决方案是定义一个接口:
type INamed =
抽象名称:字符串
类型ListEntryViewModel<'T when'T:> INamed>(model:'T)=
member this.Name = model.Name
(事实上, ListEntryViewModel
可能并不需要一个类型参数,可以只取 INAMED
作为构造函数的参数,但)
现在,您仍然可以使用duck输入并使用 ListEntryViewModel
名称属性,但不要实现 INamed
接口!这可以通过编写返回 INamed
的 inline
函数并使用静态成员约束捕获现有的名称
属性:
let inline namedModel< ^ T当^ T:(member name:string)> (模型:^ T)=
{new IN
member x.Name =
(^ T:(member Name:string)model)}
然后,您可以通过编写创建视图模型 ListEntryViewModel(namedModel someObj中)
,其中 someObj
不需要实现接口,但只需要 Name
属性。
我更喜欢这种风格,因为通过使用界面,您可以更好地记录您从模型中需要的内容。如果你有其他的对象不适合这个方案,你可以调整它们,但是如果你正在编写一个模型,那么实现一个接口是确保它暴露所有必需功能的好方法。
I'm trying to implement duck typing in F# and I spotted that you can have a member constraint in F# generics as follows:
type ListEntryViewModel<'T when 'T : (member Name : string)>(model:'T) =
inherit ViewModelBase()
member this.Name with get() = model.Name
However, the above code won't compile when I try to reference the property. I get a compiler error:
This code is not sufficiently generic. The type variable ^T when ^T : (member get_Name : ^T -> string) could not be generalized because it would escape its scope.
Is it possible to implement duck typing via a generic constraint?
There was a similar question recently where member constraints were used in the type declaration.
I'm not sure how to correct your sample to make it compile, but I would not be surprised if that was not possible. Member constraints are designed to be used with statically resolved type parameters and especially with inline
functions or members and I do not think it is idiomatic F# code to use them with type parameters of a class.
I think that a more idiomatic solution to your example would be to define an interface:
type INamed =
abstract Name : string
type ListEntryViewModel<'T when 'T :> INamed>(model:'T) =
member this.Name = model.Name
(In fact, the ListEntryViewModel
probably does not need a type parameter and can just take INamed
as a constructor parameter, but there may be some benefit in writing it in this way.)
Now, you can still use duck typing and use ListEntryViewModel
on things that have Name
property, but do not implement the INamed
interface! This can be done by writing an inline
function that returns INamed
and uses static member constraints to capture the existing Name
property:
let inline namedModel< ^T when ^T : (member Name : string)> (model:^T)=
{ new INamed with
member x.Name =
(^T : (member Name : string) model) }
You can then create your view model by writing ListEntryViewModel(namedModel someObj)
where someObj
does not have to implement the interface, but needs just the Name
property.
I would prefer this style, because by taking an interface, you can better document what you require from the model. If you have other objects that do not fit the scheme, you can adapt them, but if you're writing a model, then implementing an interface is a good way to make sure it exposes all the required functionality.
这篇关于F#泛型类型约束和鸭子打字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!