假设我有一个重要的类层次结构:
Tag
ControlFlowTag
IfTag
ForTag
JumpTag
HTMLTag
DivTag
我希望制作一个穿插这些和字符串的列表。
let MyList = [tagA, tagB, "some text", tagC]
我认为我可以区别对待它
type Node =
| Tag of Tag
| String of String
let MyList: list<Node> = [tagA, tagB, "some text", tagC]
但是,如果没有
,它就不起作用let MyList: list<Node> = [Tag tagA, Tag tagB, String "some text", Tag tagC]
显然,Node中描述的Tag和String是正交的,与现有的Tag / String类分开。鼠标悬停为我提供Node.Tag
和Node.String
类型,这不是我想要的。
我现在拥有的是一个功能t
,它会创建一个继承自StringTag
的{{1}},给我
Tag
非常好,但额外的let MyList : list<Tag> = [tagA, tagB, t"some text", tagC]
会增加视觉噪音。我真正想要的是一个强类型的“两种不同类型的列表”,我可以使用t
语句来处理它。我认为这是歧视联盟的重点,但他们无法使用现有的类型层次结构是一个问题,因为现有的层次结构(在这种情况下match
)足够复杂我认为对该子集的完全OO-继承方法类型比纯粹的歧视联盟方法更清晰
一个选项就是让它成为Tag
的列表并在obj
之前/期间投射所有内容,但这并不是很好。还有其他方法吗?
答案 0 :(得分:8)
如果您有两个不同的DU,请说
type Node =
| Tag of Tag
| String of String
和
type Foo =
| Bar of Tag
| Name of String
编译器如何知道以下列表是哪种类型的?
[tagA; tagB; "some text"; tagC]
正如斯维克所说,鉴别者是必要的。如果你使用类而不是你需要向上转换为基类型,所以我不确定你是否节省了击键次数。
如果您正在使用词典,here是减少拳击语法噪音的不错选择。也许你可以为列表做类似的事情。
答案 1 :(得分:8)
我不知道这有多大帮助,但您可以使用Active Patterns以类似DU的方式匹配类层次结构。
[<AbstractClass>]
type Animal() =
abstract Talk : string
type Cat() =
inherit Animal()
override this.Talk = "Meow"
type Dog() =
inherit Animal()
override this.Talk = "Woof"
type SuperCat(s) =
inherit Cat()
override this.Talk = s
let animals : list<Animal> =
[Dog(); Cat(); SuperCat("MEOW")]
let (|SCSaid|_|) (a:Animal) = // Active Pattern
match a with
| :? SuperCat as sc -> Some sc.Talk
| _ -> None
for a in animals do
match a with
| :? Dog -> printfn "dog"
| SCSaid s -> printfn "SuperCat said %s" s // looks like DU
| _ -> printfn "other"
//dog
//other
//SuperCat said MEOW
答案 2 :(得分:2)
受歧视的工会只是 - 有区别的(与C联盟不同)。这意味着您必须始终添加鉴别器。
如果这是C#,我会考虑从string
隐式转换为StringTag
。但由于F#不支持隐式转换,我认为第二种方法是你最好的选择。虽然我会使函数的名称更具描述性,而不仅仅是t
。大多数情况下,编写易于阅读的代码更好,而不是编写易于编写的代码。