0

我想在资源使用过程中出现任何异常时释放资源。

在 C++ 中,这个任务很简单:我将发布放入析构函数中,无论发生什么,它都会自动调用。在 Java 中使用“finally”子句。标准 ML 中相同任务的实践是什么?

我试图用变量模式'e'捕获所有异常并重新引发它:

datatype FileReadResult = FileReadOkay of string | FileReadError

fun read_file (file_path_string : string) : FileReadResult =
    let
        val istream = TextIO.openIn file_path_string
            (* this file is my resource *)
    in
        TextIO.closeIn istream;
        FileReadOkay "" (* the content of the file will go here *)
        handle e => (TextIO.closeIn istream; raise e)
    end
    handle Io => FileReadError

我的编译器 (MLton) 接受它,但因为我是 ML 新手,所以我在这里要求确保这确实是正确的 | 最佳实践。

由于这是一种常见的设计模式,我创建了以下实用函数来表达它:

(* Uses the given resource in the given way while releasing it if any exception occurs. *)
fun use_resource (resource : 'Resource) (releaser : 'Resource -> unit) (usage : unit -> 'Result) : 'Result = 
    let
        val r = usage ()
    in
        releaser resource;
        r
    end
    handle e => (releaser resource; raise e)

此函数的作用与 C# 中的“使用”功能相同。

4

1 回答 1

3

是的,这是通常的模式,有两个警告:

  1. 内部handleFileReadOkay ""你代码中唯一的,永远不会抛出。您想在代码的较大部分加上括号,以便处理程序适用于所有代码。
  2. 您的外部处理程序捕获Io. 我认为您的意思是IO.Io _这里,否则您将捕获每个异常(因为Io只是一个随机的新鲜变量)。

如果频繁出现,也可以尝试将其抽象为一个函数。类似的东西

(* withTextFile : string -> (TextIO.instream -> 'a) -> 'a
fun withTextFile name f =
    let
        val is = TextIO.openIn name
    in
        (f is before TextIO.closeIn is)
        handle e => (TextIO.closeIn is; raise e)
    end

(中缀运算符before计算其左侧和右侧表达式并返回前者的结果)。像这样使用它:

fun echo file = withTextFile file (fn is => print(TextIO.inputAll is))
于 2013-06-30T12:48:33.400 回答