构造函数中的F#引用,数组和自标识符

时间:2013-03-28 08:29:09

标签: f# websharper

我认为这是F#的一个众所周知的限制,但我找不到任何好的解决方法......

所以,这是代码(我试图让它变得尽可能简单,所以看起来它似乎没有任何意义):

[<ReflectedDefinition>]
type Human (makeAName: unit -> string) as self =
    let mutable cats : Cat array = [| |]
    do
        // get a cat
        cats <- Array.append cats [| new Cat (self, makeAName ()) |]
    member this.Cats = cats
and
 [<ReflectedDefinition>]
 Cat (owner : Human, name : string) = class end

编译器说:

  

错误FS0452:引号不能包含内联汇编代码或数组上的模式匹配

实际上,as self和数组属性getter的组合打破了一切。

这里的要点是:

  • 我真的想使用数组,因为我希望WebSharper将我的集合转换为JavaSript数组。
  • 我真的需要构造函数中的自我标识符。
  • 我真的需要课程(即功能风格不起作用)。
  • 每个方法的自我标识符(member this.Foo)工作正常。

我能想到的一个解决方法是将构造函数设为私有,并使用静态方法构造对象。这样我就不需要as self。但这很愚蠢。

还有更好的选择吗?


更新

这是一个更简单的例子:

[<ReflectedDefinition>]
type User (uid: int) as self =
    let ROOT_UID = 0
    member this.isRoot = (uid = ROOT_UID)

使用as self我甚至无法定义类常量。嗯,这实际上是一个单独的问题,但我会在这里问:在这种特殊情况下如何定义类常量?


1 个答案:

答案 0 :(得分:8)

我认为这根本不是愚蠢的。我们实际上更喜欢静态构造函数方法,即使在不使用WebSharper的代码中也是如此。在整个IntelliFactory代码库中,我们很少使用self

您正在遇到F#编译器和报价的两个令人讨厌的限制。正如您所指出的,静态方法可以解决self问题:

[<ReflectedDefinition>]
type Human private (cats: ref<Cat []>) =
    member this.Cats = !cats

    static member Create(makeAName: unit -> string) =
        let cats = ref [| |]
        let h = Human(cats)
        let cat = Cat(h, makeAName())
        cats := [| cat |]
        h

and [<ReflectedDefinition>] Cat (owner: Human, name: string) =
    class
    end

还有很多其他方法可以实现这一点,例如你可以摆脱ref间接。

其次,即使在纯静态方法中,您经常在FS0452代码中使用数组操作获得ReflectedDefinition。这通常可以通过使用库函数而不是直接数组访问来解决(Array.iterArray.map)。

对于第二个例子,你真的想要这个:

[<ReflectedDefinition>]
module Users =

    [<Literal>]     
    let ROOT_UID = 0

    type User(uid: int) =
        member this.isRoot = (uid = ROOT_UID)

[<Literal>]注释将允许您对常量进行模式匹配,如果存在多个常量,则可以很方便。

对于你的观点:

  1. 我真的想使用数组 - 应该没问题
  2. 我真的需要一个自我标识符 - 它永远不需要,就像构造函数不是
  3. 一样
  4. 我真的需要课程(即功能风格不起作用) - 绝对不是真的
  5. 每个方法的自我标识符(成员this.Foo)工作正常 - 是的,并且很有用