Klasseninstanz Typumwandlung in Modulsignatur
Frage
Einige meiner Module enthalten globale Klasseninstanzen, die einen bestimmten Klassentyp mit zwei Methoden, private_method
und public_method
implementieren.
Ich mag MyModule.my_instance # public_method
von überall in meinem Programm zur Verfügung steht, und MyModule.my_instance # private_method
nur innerhalb MyModule
zur Verfügung.
Ich habe folgendes versucht:
class type public_type = object
method public_method : int
end ;;
class type private_type = object
method public_method : int
method private_method : int
end ;;
let make_private : unit -> private_type = fun () -> object
method public_method = 0
method private_method = 0
end ;;
module type MY_MODULE = sig
val my_instance : public_type
end
module MyModule : MY_MODULE = struct
let my_instance = make_private ()
let _ = print_int (my_instance # private_method)
end
Dies führt jedoch zu einem Fehler:
Werte nicht übereinstimmen:
val my_instance : private_type
ist nicht in inbegriffen
val my_instance : public_type
I könnte schreiben Sie den Zwang manuell:
module MyModule : MY_MODULE = struct
let my_instance = make_private ()
let _ = print_int (my_instance # private_method)
let my_instance = (my_instance :> public_type)
end
Aber ich würde lieber nicht doppelt die Codegröße für etwas so einfaches wie diese.
Haben Sie Vorschläge, warum dies geschieht, und wie kann ich es umgehen?
Lösung
Es gibt keine impliziten Nötigungen in ocaml. Vielleicht ist es wert Zwang in Funktors setzen (wenn Sie mehrere Module mit den gleichen Eigenschaften haben):
module Hide(M:sig val my_instance : private_type end) : MY_MODULE =
struct
let my_instance = (M.my_instance :> public_type)
end
module MyModule = Hide (struct
let my_instance = make_private ()
let _ = print_int (my_instance # private_method)
end)
Andere Tipps
Wahrscheinlich die beste Technik, um dies zu lösen, ist Privat Reihe zu verwenden Typen wie Garrigue beschrieben ( „private Zeilentypen: Abstrahieren die Unbenannt“, bitte schauen, wie ich nicht einen zweiten Link, um es veröffentlichen kann). Dies kann mit einem expliziten Objekttyp Ausdruck verwendet werden:
module type MY_MODULE2 = sig
type t = private < public_method : int; ..>
val my_instance : t
end ;;
module MyModule2 : MY_MODULE2 = struct
type t = private_type
let my_instance = make_private ()
let _ = print_int (my_instance # private_method)
end ;;
oder mit einem Objektpfad (das ist, was Sie benötigen):
module type MY_MODULE3 = sig
type t = private #public_type
val my_instance : t
end ;;
module MyModule3 : MY_MODULE3 = struct
type t = private_type
let my_instance = make_private ()
let _ = print_int (my_instance # private_method)
end ;;