类型测试为联合测试表达式生成错误



我的问题与以下程序有关。

open System
// Types
type Car (brand: string) =
member _.Brand = brand
type BMW () =
inherit Car "BMW"
type Pet =
| Cat
| Dog
[<EntryPoint>]
let main argv =
// Match subtype of test-expression type: ok
let car = Car "Mercedes"
let carResult =
match car with
| :? BMW -> 1
| _ -> 0
// Match type of test-expression: "will always hold" warning
let bmw = BMW ()
let bmwResult =
match bmw with
| :? BMW -> 1
| _ -> 0
// Catch any exception: "will always hold" warning
let exceptionResult =
try
1/0
with
| :? Exception -> 2
// Match type of test-expression (union type): "The type 'Pet' does not have any proper subtypes" error
let cat = Cat // this has type Pet
let catResult =
match cat with
| :? Pet -> 1
| _ -> 0
0

在第一个测试中,测试表达式的类型为Car,类型测试模式中的类型BMW是其中的一个子类型,并且没有警告或错误。在第二个和第三个测试中,类型测试模式中的类型与测试表达式的类型相同,并且会发出警告,这是可以理解的,因为当程序员测试BMW是否真的是BMW,或者Exception是否真的为Exception时,这很可能是一个逻辑错误。

最后一个测试的形式与测试二和测试三相同:测试表达式的类型为Pet,类型测试模式也是Pet。那么,为什么在这种情况下会产生错误呢?错误显示The type 'Pet' does not have any proper subtypes...。但是BMW没有任何子类型,也没有产生这个错误。此外,模式匹配页面(在"类型测试模式"下(说,"如果输入类型与模式中指定的类型匹配(或派生类型(,则匹配成功。"PetPet、ergo等匹配。为什么联合类型被区别对待?

也许错误消息的措辞有点过于含糊。这并不是说类型Pet没有子类型,而是它不能有子类型。

因为BMW是一个类,所以它可能有一个来自不同程序集的子类型,该程序集是在定义BMW本身的程序集之后编译的。

但对于Pet,这是不可能发生的,因为sum类型不能有子类型,因此禁止对这些类型进行继承匹配。

还要注意,错误的来源是要匹配的变量的类型,而不是模式的类型。因此,例如,这将在没有错误的情况下编译:

let n : obj = null
match n with
| :? Pet -> "is a pet"
| _ -> "no idea"

这是有效的,因为n的类型是obj确实有子类型,其中Pet是其中之一(毕竟这是.NET,一切都是对象(。但是,对变量cat进行匹配是不起作用的,因为该变量本质上是一种无子类型的类型。

最新更新