我有一个坐标" class" (在OCaml中使用返回对象文字的工厂函数实现)并且我试图弄清楚如何将该对象上方法的可见性限制为它所定义的模块。
这是源文件
(* coordinate.ml *)
type coordinate = < get_x : int; get_y : int >
let create_coord ~x ~y = object
val x = x
val y = y
method get_x = x
method get_y = y
(* hide this method from public interface *)
method debug_print = Printf.printf "(x=%d, y=%d)\n"
end
这是界面
(* coordinate.mli *)
(* the type synonym coordinate is compatible with the "real"
* type, but does not expose the debug_print method *)
type coordinate = < get_x : int; get_y : int >
val create_coord : x:int -> y:int -> coordinate
我的目的是允许create_coord
返回的对象在Coordinate
模块的主体内部显示所有方法。在coordinate
文件中重复.ml
类型别名的唯一原因是为了满足编译器/允许它在.mli
中使用。
但是,我想阻止此模块的使用者使用debug_print
方法。我认为,&#34;因为OCaml支持结构类型&#34;,具有严格较少方法的对象类型将是&#34;兼容的&#34;类型为类型归属。
但是,当我尝试编译文件时,我收到以下错误:
$ ocamlc coordinate.mli
$ ocamlc coordinate.ml
File "coordinate.ml", line 1:
Error: The implementation coordinate.ml
does not match the interface coordinate.cmi:
Values do not match:
val create_coord :
x:'a ->
y:'b ->
< debug_print : int -> int -> unit; get_x : 'a; get_y : 'b >
is not included in
val create_coord : x:int -> y:int -> coordinate
File "coordinate.ml", line 3, characters 4-16: Actual declaration
Exit 2
有没有办法限制debug_print
Coordinate
在string = "A"
secret_word = "Apple"
if string in secret_word:
print("Good!")
else:
print("Bad...")
之外的可见度,同时让它在内部可以自由访问?
答案 0 :(得分:4)
我认为最好的解决方案是使用私有行类型:
module M : sig
type t = private < x : int; y : int; .. >
val make : int -> int -> t
val f: t -> unit
end = struct
type t = < x : int; y : int; z : [`Not_exposed] >
let make x y = object
method x = x
method y = y
method z = `Not_exposed
end
let f o =
(* Access a method not exposed outside of the module *)
assert (o#z = `Not_exposed)
end;;
这样,您不需要任何强制功能。尽管如此,任何类型为t
的对象都可以在模块M中看到他的私有方法,但只能在外部访问公共方法(x
和y
)。在manual。
答案 1 :(得分:2)
你可以通过明确的强制来完成一些工作。一个最小的例子:
../configure CC=icc CXX=icpc FC=ifort CFLAGS="-D_Float128=__float128"
仍然隐藏了type t = < x : int; y : int >
let make x y : t =
let o =
object
method x = x
method y = y
method z = `Not_exposed
end
in
(o :> t)
(* val make : int -> int -> t = <fun> *)
内部模块。您可以通过隐藏z
:
make
但是这不允许您将module M : sig
type t = < x : int; y : int >
val make : int -> int -> t
end = struct
type t = < x : int; y : int >
let make x y = object
method x = x
method y = y
method z = `Not_exposed
end
let f o =
(* Access a method not exposed outside of the module *)
assert (o#z = `Not_exposed)
(* Shadow the make function, coercing the result into type t *)
let make x y =
(make x y :> t)
end
公开为f
,因为t -> unit
没有t
方法。
您还可以公开两种类型,将完整对象类型抽象保留在模块的上下文之外,并提供强制/转换为公开的,更受限制的类型的函数:
z
答案 2 :(得分:1)
对于后代,我发现可以使用显式的多态类型和显式的向上转换来使OCaml确信可以“忘记”一种方法。
type kata = < foo : int; bar : string >
type ana = < foo : int >
let to_ana (k : < foo : int ; .. >) : ana = (k :> ana)
这与多态代码一起很好地工作。
to_ana (object method foo = 42 method bar = "asdf" method baz = [] end)