julia 中类型稳定的 do 块

Type-stable do-blocks in julia

我想从带有 do 块的文件中读取数据。使用 do-block 非常重要,因为即使在读取文件期间发生错误,我也需要确保文件正确关闭。文件中的数据应转换为作为参数提供的类型。我的实际用例是使用 NetCDF 文件,但我可以用纯文本文件重现类型稳定性问题。

假设,有一个文件 file.txt,其内容为 123,可以通过以下方式创建:

 write("file.txt","123")

当我按如下方式加载没有 do 块的文件时,结果类型稳定:

function loadfile1(T)
    f = open("file.txt")
    data = parse(T,readline(f))
    close(f)
    return data
end

@code_warntype 正确推断出我得到 Float32 作为结果:

@code_warntype loadfile1(Float32)
Body::Float32
[...]

但是,以下变体:

function loadfile2(T)
    f = open("file.txt") do f
        return parse(T,readline(f))
    end
end

生成类型不稳定的代码:

 @code_warntype loadfile2(Float32)
Body::Any
9 1 ─ %1 = %new(getfield(Main, Symbol("##842#843")){DataType}, T)::getfield(Main, Symbol("##842#843")){DataType}                                                                                  │ 
  │   %2 = Main.open::Core.Compiler.Const(open, false)                                                                                                                                            │ 
  │   %3 = invoke Base.:(#open#294)($(QuoteNode(Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}()))::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, %2::Function, %1::getfield(Main, Symbol("##842#843")){DataType}, "file.txt"::String)::Any
  └──      return %3            

如何修改函数 loadfile2(使用 do 块)并仍然获得类型稳定的结果?

可以将 T 移动到签名中的类型规范:

function loadfile2(::Type{T}) where T
    f = open("file.txt") do f
        return parse(T,readline(f))
    end
end

这种方式T在编译时已知。