我正在玩方法重新定义,我发现了这个愚蠢的例子:
class a =
object
method get (x : a) = x
end
class b =
object
inherit a
method get (x : b) = x
end
我明确指出我希望b类中的get方法取b并返回b,但方法签名是 - >一个。如果我这样做 (新b)#get(新a) 当他真的不应该,他很开心。在那之后我添加了一些愚蠢的东西:
class a =
object
method get (x : a) = x
end
class b =
object
inherit a
method get (x : b) = x#foo(x)
method foo (x : a) = x
end
我得到Error: This expression has type b
It has no method foo
究竟发生了什么?
答案 0 :(得分:5)
首先采用第一个例子:OCaml具有对象的结构类型,而不是标称类型。换句话说,对象的类型完全由其方法(及其类型)决定。因此,类a
和b
实际上是同一类型。
$ ocaml
OCaml version 4.00.0
# class a = object method get (x: a) = x end;;
class a : object method get : a -> a end
# class b = object inherit a method get (x: b) = x end;;
class b : object method get : a -> a end
# let a0 = new a;;
val a0 : a = <obj>
# let b0 = new b;;
val b0 : b = <obj>
# (a0: b);;
- : b = <obj>
# (a0: a);;
- : a = <obj>
# (b0: a);;
- : a = <obj>
# (b0: b);;
- : b = <obj>
#
(我在此处展示的是,a0
和b0
都属于a
类型{em}和类型b
。 )
在第二个例子中,我要说你试图给get
方法一个新类型。在OCaml中覆盖方法时,参数和返回类型必须与父类中的相同。
错误消息似乎很不幸。我的猜测是,编译器认为b
类型是类型a
的另一个名称。
OCaml的优势之一是它会推断类型。如果您在课程: b
中取消get
参数b
,则会收到以下错误:
This expression has type a. It has no method foo
这有点帮助,因为它显示(我认为)您需要为参数设置a
类型。
副评论(原谅我):如果你从主流OO语言来到OCaml的OO部分,它可能会让你感到奇怪。但是如果你首先学习OCaml的FP部分,你可能会想知道为什么所有主流的OO语言都会出现这么多错误:-)。 (当然,一切都是权衡,并且没有一种正确的方法来计算结构。但是OCaml的OO子系统正在做一些相当令人印象深刻的事情。)