我正尝试了解有关inline
和SRTP的更多信息。不幸的是,我没有使这个样本最小化的理解,但是它并不太大:
type ComponentCollection<'props, 'comp when 'props : comparison> =
{
Components : Map<'props, 'comp>
}
with
static member AddComponent (collection, props, comp) =
{
Components =
collection.Components
|> Map.add props comp
}
module ComponentCollection =
let inline add< ^t, ^props, ^comp
when ^t : (static member AddComponent : ((^t * ^props * ^comp) -> ^t)) >
(props : ^props) (comp : ^comp) (xs : ^t) =
(^t : (static member AddComponent : (^t * ^props * ^comp -> ^t ) ) () ) (xs, props, comp)
type Component<'t> =
{
Props : 't
}
type Foo =
{
Foo : int
}
[<EntryPoint>]
let main argv =
let foo = { Foo = 1 }
let a : ComponentCollection<Foo, Component<Foo>> =
{ Components = Map.empty }
|> ComponentCollection.add foo { Props = foo }
0
给出编译错误:
错误FS0001:类型'ComponentCollection <'a,'b>'不支持运算符'get_AddComponent'
由于我使用的是static member AddComponent
,而不是get_AddComponent
,所以这对我来说是非常误导的。我不确定编译器从何处获得get_AddComponent
。
我在这里做什么错了?
另外,如果有人可以解释这段代码,这将非常有帮助:
(^t : (static member AddComponent : (^t * ^props * ^comp -> ^t ) ) () )
我知道它以某种方式提供了static
的{{1}}成员AddComponent
作为自由函数,但是我将其与其他示例结合在一起,并且缺少该语法的文档。例如,为什么需要^t
?
答案 0 :(得分:2)
据我所知,您的代码片段唯一有问题的地方是您有一些多余的括号,不幸的是,在这种情况下,括号实际上具有语义含义。如下更改代码即可解决问题:
module ComponentCollection =
let inline add< ^t, ^props, ^comp
when ^t : (static member AddComponent : ^t * ^props * ^comp -> ^t) >
(props : ^props) (comp : ^comp) (xs : ^t) =
(^t : (static member AddComponent : ^t * ^props * ^comp -> ^t) (xs, props, comp))
问题在于F#实际上在以下方面有所作为:
static member AddComponent : ^t * ^props * ^comp -> ^t
static member AddComponent : (^t * ^props * ^comp) -> ^t
static member AddComponent : ((^t * ^props * ^comp) -> ^t)
关于您的第二个问题-在工作版本中,呼叫如下:
(^t : (static member AddComponent : ^t * ^props * ^comp -> ^t) (xs, props, comp))
这告诉编译器访问静态成员(约束要求),并使用参数xs
,props
和comp
调用它。在您的原始版本中,这是在调用该属性的getter方法(但是令人困惑的是,它以某种方式允许您在不使用参数的情况下执行此操作-我怀疑以后会导致另一种类型的错误)。
答案 1 :(得分:2)
根据经验,SRTP非常复杂且难以使用。它们需要大量inline
,并且错误消息往往非常晦涩。
我建议限制使用它们。 另外,如果您对此感兴趣,它们将不兼容C#。
我还更改了您的代码以解决问题:
type ComponentCollection<'props, 'comp when 'props : comparison> =
{
Components : Map<'props, 'comp>
}
with
member collection.AddComponent(props, comp) =
{
Components =
collection.Components
|> Map.add props comp
}
module ComponentCollection =
let inline add< ^t, ^props, ^comp
when 'props : comparison and ^t : (member AddComponent : ^props * ^comp -> ^t) >
(props : ^props) (comp : ^comp) (xs : ^t) =
(^t : (member AddComponent : ^props * ^comp -> ^t ) (xs, props, comp ))
type Component<'t> =
{
Props : 't
}
type Foo =
{
Foo : int
}
[<EntryPoint>]
let main argv =
let foo = { Foo = 1 }
let a =
{ Components = Map.empty }
|> ComponentCollection.add foo { Props = foo }
0