【问题标题】:Overriding Exception.Message / exception pattern matching覆盖 Exception.Message / 异常模式匹配
【发布时间】:2011-02-17 18:45:37
【问题描述】:

我正在尝试对其定义中的异常进行模式匹配。是否可以使用 F# 的异常语法,或者我必须继承 Exception

这是我期望的工作:

exception CoordErr of int * int
    with
        override this.Message = 
            let CoordErr(x, y) = this
            sprintf "(%i %i)" x y //ERROR

但会产生错误:

未定义值或构造函数“x”
未定义值或构造函数“y”

编辑

我也尝试添加括号:

let (CoordErr(x, y)) = this

但这给出了错误:

这个表达式应该有 exn 类型,但这里有 CoordErr 类型

更新

以下方法可行,但并不理想:

exception CoordErr of int * int
    with
        override this.Message = 
            sprintf "(%i %i)" this.Data0 this.Data1

还有其他方法吗?

更新 2

从 kvb 的回答中得到提示,我想我可以执行以下操作来吞下 incomplete matches 警告:

exception CoordErr of int * int
    with
        override this.Message = 
            match this :> exn with
            | CoordErr(x, y) -> sprintf "(%i %i)" x y
            | _ -> Unchecked.defaultof<_>

【问题讨论】:

  • 我会把它从 Unchecked.defaultof&lt;_&gt; 改成 failwith "impossible"

标签: exception f# pattern-matching


【解决方案1】:

您的第一次尝试没有成功,因为您定义了一个名为 CoordErr 的 let-bound 函数,它隐藏了异常构造函数,这不是您想要的。

您的第二次尝试几乎成功了。不幸的是,异常定义不像可区分联合那样工作:当对异常构造函数进行模式匹配时,您要匹配的表达式必须是 exn 类型(而不是特定异常子类型)。在您的情况下,您正在尝试将 thisCoordErr 类型)与 CoordErr 构造函数进行匹配。解决方法如何?

exception CoordErr of int * int
    with
        override this.Message = 
          let (CoordErr(x,y)) = upcast this
          sprintf "(%i %i)" x y

【讨论】:

  • 这很棒(incomplete pattern matches 警告是一个小烦恼,但哦,好吧)。你能解释一下向上转型的必要性吗?
  • 没关系。你显然是按照我的要求解释的。 :)
  • @kvb - 我用避免警告的代码更新了问题。有没有更好的方法?
  • @Daniel - 我同意这种行为有点奇怪(而且非常微妙)。但在某种程度上,它看起来确实是一致的:let e = CoordErr(1,2) 导致e 具有静态类型exn,而不是CoordErr,因此CoordErr 用于破坏exn 值时用作也是一种模式。
  • @Daniel - 我会改用#nowarn "25",因为您知道在这种情况下模式将始终匹配。
【解决方案2】:

命名构造函数参数并访问相应的字段似乎可行:

exception CoordErr of x : int * y : int
    with
        override this.Message = 
            sprintf "(%i %i)" this.x this.y

我意识到这不是模式匹配解决方案,但它确实回答了您问题的“覆盖 Exception.Message”部分。 :)

【讨论】:

  • 这可能是最干净的解决方案,但是当我问这个问题时,命名联合字段尚未添加到 F#。
  • 明白,刚刚为以后的访问者添加了这个:)
【解决方案3】:

您可以使用 try with expression 的异常感知模式匹配

exception CoordErr of int * int
    with
        override this.Message = 
            try raise this with CoordErr(x, y) -> sprintf "(%i %i)" x y

【讨论】:

  • 这远非理想,因为饲养和捕捉比常规操作需要更多的时间。哪怕只做一次,也是很不好的习惯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多