Dav*_*ind 8 inheritance ocaml types class object
在Ocaml中,我正在努力进行子类化和类型化:
class super =
object (self)
method doIt =
...
end;
class sub =
object (self)
inherit super
method doIt =
...
self#somethingElse
...
method somethingElse =
...
end;
let myFunction (s:super) =
...
myFunction new sub
Run Code Online (Sandbox Code Playgroud)
显然OCaml中,阶级sub是不是一类的"子" super,因为该sub#doIt方法调用的方法sub是不存在的super.但是,这似乎是OO编程的一个非常常见的用例.推荐的方法是什么?
正如Rémi所提到的,代码的问题在于OCaml类型系统每个表达式只支持一种类型:类型的表达式sub不是类型super.在您的示例中,myFunction期望一个类型的参数super,并且表达式new sub是类型sub,因此是问题.
向上转换对于面向对象的编程至关重要,而OCaml确实用两种不同的结构来支持它.
首先是类型强制.如果super是超类型sub(意味着在语义上,类型的sub值表现为值super)x : sub,那么(x :> super) : super.该:>类型的操作,使转换明确的-当你使用类型的安勤哪些流行的面向对象语言含蓄地做相当于sub其中super的预期.
第二种是超类型约束:要求给定的类型变量是给定类型的子类型.这被写成#super或者(#super as 'a)如果你想名称中的类型变量.超类型约束实际上并没有像强制类型那样改变表达式的类型,它们只是检查类型是否是所需类型的有效子类型.
要更加了解这种差异,请考虑以下示例:
class with_size ~size = object
val size = size : int
method size = size
end
class person ~name ~size = object
inherit with_size ~size
val name = name : string
method name = name
end
let pick_smallest_coerce (a : with_size) (b : with_size) =
if a # size < b # size then a else b
let pick_smallest_subtype (a : #with_size) (b : #with_size) =
if a # size < b # size then a else b
Run Code Online (Sandbox Code Playgroud)
类型pic_smallest_coerce是with_size -> with_size -> with_size:即使您传递了两个person实例,返回值也是类型with_size,您将无法调用其name方法.
类型pic_smallest_subtype是(#with_size as 'a) -> 'a -> 'a:如果传递两个person实例,类型系统将确定'a = person并正确地将返回值标识为类型person(允许您使用该name方法).
简而言之,超类型约束只是确保您的代码运行,而不会丢失任何类型信息 - 变量保留其原始类型.类型强制实际上会丢失类型信息(在没有向下转换的情况下,它是一个非常讨厌的东西),所以它应该只在两种情况下作为最后的手段:
1.你不能拥有多态函数.超类型约束依赖于#super自由类型变量,因此如果您无法承担代码中的自由类型变量,则必须不使用它.
2.您需要在同一容器中实际存储不同实际类型的值.可以包含person或box实例的列表或引用将使用with_size和强制:
let things = [ my_person :> with_size ; my_box :> with_size ]
Run Code Online (Sandbox Code Playgroud)
请注意,类型推断算法将自己发现超类型约束(它不会确定您要使用的类或类类型,但它将构造一个文字类类型):
let pick_smallest_infer a b =
if a # size < b # size then a else b
val pick_smallest_infer : (< size : 'a ; .. > as 'b) -> 'b -> 'b
Run Code Online (Sandbox Code Playgroud)
因此,除了极少数例外,仅在记录代码时才注释实际的超类型约束是一项有用的练习.
sub可能是super的子类型.但是在ocaml中没有隐式类型转换.所以你的函数不接受super的子类型.你必须明确强制:
let myFunction (s:super) =
...
myFunction (new sub :> super)
Run Code Online (Sandbox Code Playgroud)
或者最好接受super的子类型:
let myFunction (s:#super) =
...
myFunction new sub
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1308 次 |
| 最近记录: |