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
在编译时已知。
我想从带有 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
在编译时已知。