1

考虑以下情况:

struct A <: AbstractArray{Int, 2}
    N::Int
end

struct B <: AbstractArray{Int, 2}
    A::A
    Func
end
...
@inline Base.getindex(A::A, i::Int, j::Int) = begin
    @boundscheck (1 <= i <= A.N && 1 <= j <= A.N) || throw(BoundsError())
    i - j
end

Base.@propagate_inbounds Base.getindex(B::B, i::Int, j::Int) = begin
    B.Func(B.A[i, j])
end

查看文档和一些示例,我确信在执行“@inbounds b[i, j]”(b 是 B 类型的数组)时会消除边界检查。然而,事实并非如此。我错过了什么?

4

1 回答 1

4

这仅使用您的定义对我有用:

julia> f1(x, i, j) = return x[i,j]
       f2(x, i, j) = @inbounds return x[i,j]

julia> f1(A(5), 123, 123)
ERROR: BoundsError
Stacktrace:
 [1] getindex at ./REPL[3]:2 [inlined]
 [2] f1(::A, ::Int64, ::Int64) at ./REPL[4]:1

julia> f2(A(5), 123, 123)
0

julia> f1(B(A(5), identity), 123, 123)
ERROR: BoundsError
Stacktrace:
 [1] getindex at ./REPL[3]:2 [inlined]
 [2] getindex at ./REPL[3]:6 [inlined]
 [3] f1(::B, ::Int64, ::Int64) at ./REPL[4]:1

julia> f2(B(A(5), identity), 123, 123)
0

正如我在评论中提到的,@inbounds只有在类型稳定的函数中才有效。在全局范围(如 REPL)或在类型不稳定的函数(如引用非常量全局或抽象类型字段或数组的函数)中测试它不会删除这些边界检查。

请注意,您的定义B可能会导致类型不稳定,因为 Julia 无法知道它存储的是什么函数。它们在您发布的最小示例中并不明显,但这可能是您更复杂的原始问题的根本原因。更好的定义是:

struct B{F} <: AbstractArray{Int, 2}
    A::A
    Func::F
end
于 2018-04-11T03:52:05.740 回答