非可空字符串的F#类型别名

Tom*_*han 9 f#

我的代码中有几个域类型用于区分不同类型的字符串,因此编译器可以阻止我以错误的顺序传递参数:

type Foo = string
type Bar = string

let baz (foo : Foo) (bar : Bar) = printfn "%A %A" foo bar

let f : Foo = "foo"
let b : Bar = "bar"

baz f b // this should be OK
baz b f // this shouldn't compile
Run Code Online (Sandbox Code Playgroud)

但是,这目前无法令人满意地工作,原因有两个:

  • 我无法找到指定null不是有效值的方法,所以我不能保证Foo实例永远不会null.
  • 两个incantantions实际上编译(并运行) - 所以我什么都没得到:D

有没有办法定义类型别名

a)引用/包装相同类型,但彼此不兼容,并且b)禁止null值,即使基础类型允许它?

kvb*_*kvb 10

别名可以自由替换,因此没有办法将它们用于此目的,但您可以使用单一案例区分联盟.使用智能构造函数来阻止使用null和私有实现(以便在模块之外的代码定义它们不能绕过智能构造函数),你应该基本上得到你想要的东西(尽管在运行时强制执行null的检查)而不是编译时间,遗憾地):

type Foo = private Foo of string with
    static member OfString(s) =
        if s = null then failwith "Can't create null Foo"
        else Foo s

type Bar = private Bar of string with
    static member OfString(s) =
        if s = null then failwith "Can't create null Bar"
        else Bar s

let baz (foo : Foo) (bar : Bar) = printfn "%A %A" foo bar
let f = Foo.OfString "foo"
let b = Bar.OfString "bar"
baz f b // ok
baz b f // type error
Run Code Online (Sandbox Code Playgroud)

  • 请参阅http://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/,以便通过这种方式对其进行深入处理. (3认同)