F#cast和泛型

时间:2009-12-12 19:32:28

标签: generics f# casting

尝试学习一些F#,我遇到了几个挂断。

以下是代码:

#light
module HtmlModule

type HtmlString(text:string) =
    override x.ToString() = text

type HtmlAttribute(key:string, value:string) =
    inherit HtmlString(key + "=\"" + value + "\"");

type HtmlElement(tag: string, ?contents:list<'a> when 'a :> HtmlString) =
    inherit HtmlString("")
    let innerContents = defaultArg contents []
    let castToHtmlAttribute (hs:HtmlString) : Option<HtmlAttribute> =
        match hs with
        | :? HtmlAttribute as temp -> Some(temp)
        | _ -> None
    member x.tag = tag
    member x.contents = innerContents |> List.filter(fun x -> (castToHtmlAttribute x).IsNone)
    member x.attributes = innerContents |> List.map(fun x -> (castToHtmlAttribute x)) |> List.filter(fun x-> x.IsSome) |> List.map(fun x->x.Value)

    override x.ToString() =
        let sb = System.Text.StringBuilder()
        sb.Append("<" + x.tag)

        for att in x.attributes do
            sb.Append(" " + att.ToString())

        sb.Append(">")

        for item in x.contents do
            sb.Append(item.ToString())

        sb.Append("</" + x.tag + ">")
        sb.ToString()



let element tag contents = new HtmlElement(tag, contents)
let div contents = element "div" contents
let p contents = element "p" contents
let text text = new HtmlString(text)
let attr key value = new HtmlAttribute(key, value)
let classes value = attr "class" value

和一个快速控制台程序来显示问题:

#light

open HtmlModule


let stuff = [for a in 1 .. 10 do yield p [text ("some String " + a.ToString())]]

let elem = div [
            attr "class" "someClass";
            text "This is some inner text";
            div stuff;
        ]

let result = elem.ToString()
printfn "%A"  result

编译器不允许该行

div stuff;

它声明:

  

“错误7类型不匹配。期待HtmlString列表但给出HtmlElement列表类型'HtmlString'与类型'HtmlElement'不匹配”

可以将此问题跟踪到castToHtmlAttribute方法签名

 let castToHtmlAttribute (hs:HtmlString) : Option<HtmlAttribute> =

如果我像这样使这一行变得更通用:

let castToHtmlAttribute (hs:'a when 'a :> HtmlString) : Option<HtmlAttribute> =

我收到一个新错误:

  

“错误2此类运行时强制或类型测试从类型'a到HtmlAttribute涉及基于此程序点之前的信息的不确定类型。某些类型不允许运行时类型测试。需要进一步的类型注释。”

感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

这里的诊断不是很好。

您可以像这样修复代码:

let stuff = [for a in 1 .. 10 do 
               yield (p [text ("some String " + a.ToString())]) :> HtmlString]

我在基本类型中插入了一个显式的upcast。

答案 1 :(得分:1)

  

期望HtmlString列表但给出HtmlElement列表类型'HtmlString'与类型'HtmlElement'不匹配“

这很好地说明了这个问题。对于F#,List<HTMLElement>不是List<HTMLString>,而List<Orange>不是List<Fruit>

如果是,你可以写

Apple :: oranges

由于这没有任何意义,F#希望你明确地转发。只需告诉div使用通用列表。

简而言之,您可以将类型HTMLString list更改为多态#HTMLString list或手动转换参数或stuff