本文介绍了非空字符串的F#类型别名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a couple of domain types in my code that I use to distinguish different types of strings, so the compiler can stop me from e.g. passing arguments in the wrong order:

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

但是,由于两个原因,目前该方法无法令人满意地工作:

However, this currently doesn't work satisfactorily, for two reasons:

  • 我无法找出一种方法来指定 null 不是有效值,因此我无法保证 Foo 实例永远不会为 null .
  • 两个咒语实际上都可以编译(运行)-所以我什么都没得到:D
  • I haven't been able to figure out a way to specify that null is not a valid value, so I can't guarantee that a Foo instance will never be null.
  • Both incantantions actually compile (and run) - so I've gained nothing :D

有没有一种方法可以定义类型别名

Is there a way to define type aliases that

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

a) refer to/wrap the same type, but are incompatible with each-other, andb) disallow null values, even if the underlying type would allow it?

推荐答案

别名可以自由替换,因此无法为此目的使用它们,但是可以使用单格区分联合.使用避免使用null和私有实现的智能构造函数(这样,在定义它们的模块之外的代码就不会出现在智能构造函数周围),您基本上应该得到所需的内容(尽管在运行时强制执行对null的检查)而不是编译时间,可悲的是):

Aliases can be substituted freely so there's no way to use them for this purpose, but you can use single-case discriminated unions instead. With smart constructors that prevent using null and private implementations (so that code outside of the module where they're defined can't go around the smart constructors), you should basically get what you want (although the checking for null is enforced at runtime rather than compile time, sadly):

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

这篇关于非空字符串的F#类型别名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 04:33