【问题标题】:F# casting and genericsF# 强制转换和泛型
【发布时间】:2009-12-12 19:32:28
【问题描述】:

尝试学习一些 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 涉及基于此程序点之前的信息的不确定类型。在某些类型上不允许运行时类型测试。需要进一步的类型注释。”

感谢任何帮助。

【问题讨论】:

标签: generics f# casting


【解决方案1】:

这里的诊断不是很好。

您可以像这样修复代码:

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

我在其中插入了一个显式向上转换到基本类型。

【讨论】:

  • 我真的想要更多的 api,并且宁愿客户端代码不必强制转换。
  • 请考虑朱丽叶的建议。总体而言,在大多数语言中都很难编写同时涉及 List 和 List 并且不必偶尔显式转换的代码。
【解决方案2】:

需要一个 HtmlString 列表但给定一个 HtmlElement 列表类型“HtmlString”与类型“HtmlElement”不匹配”

这很好地说明了问题。对于 F#,List&lt;HTMLElement&gt; 不是 List&lt;HTMLString&gt;,就像 List&lt;Orange&gt; 不是 List&lt;Fruit&gt;

如果是,你可以写

Apple :: oranges

由于这没有任何意义,F# 期望您显式地强制转换。只需告诉 div 使用通用列表即可。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    相关资源
    最近更新 更多