【问题标题】:How to overload Base.show for custom array types?如何为自定义数组类型重载 Base.show?
【发布时间】:2019-11-20 19:51:28
【问题描述】:

假设我使用自己的自定义show 方法制作自己的自定义矢量类型:

struct MyVector{T} <: AbstractVector{T}
    v::Vector{T}
end

function Base.show(io::IO, v::MyVector{T}) where {T}
    println(io, "My custom vector with eltype $T with elements")
    for i in eachindex(v)
        println(io, "  ", v.v[i])
    end
end

如果我尝试在 REPL 中创建这些对象之一,我会收到与我从未打算调用的函数相关的意外错误:

julia> MyVector([1, 2, 3])
Error showing value of type MyVector{Int64}:
ERROR: MethodError: no method matching size(::MyVector{Int64})
Closest candidates are:
  size(::AbstractArray{T,N}, ::Any) where {T, N} at abstractarray.jl:38
  size(::BitArray{1}) at bitarray.jl:77
  size(::BitArray{1}, ::Integer) at bitarray.jl:81
  ...
Stacktrace:
 [1] axes at ./abstractarray.jl:75 [inlined]
 [2] summary(::IOContext{REPL.Terminals.TTYTerminal}, ::MyVector{Int64}) at ./show.jl:1877
 [3] show(::IOContext{REPL.Terminals.TTYTerminal}, ::MIME{Symbol("text/plain")}, ::MyVector{Int64}) at ./arrayshow.jl:316
 [4] display(::REPL.REPLDisplay, ::MIME{Symbol("text/plain")}, ::Any) at /Users/mason/julia/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:132
 [5] display(::REPL.REPLDisplay, ::Any) at /Users/mason/julia/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:136
 [6] display(::Any) at ./multimedia.jl:323
 ...

好的,无论如何我都会实现Base.size,这样我就不用管了:

julia> Base.size(v::MyVector) = size(v.v)

julia> MyVector([1, 2, 3])
3-element MyVector{Int64}:
Error showing value of type MyVector{Int64}:
ERROR: getindex not defined for MyVector{Int64}
Stacktrace:
 [1] error(::String, ::Type) at ./error.jl:42
 [2] error_if_canonical_getindex(::IndexCartesian, ::MyVector{Int64}, ::Int64) at ./abstractarray.jl:991
 [3] _getindex at ./abstractarray.jl:980 [inlined]
 [4] getindex at ./abstractarray.jl:981 [inlined]
 [5] isassigned(::MyVector{Int64}, ::Int64, ::Int64) at ./abstractarray.jl:405
 [6] alignment(::IOContext{REPL.Terminals.TTYTerminal}, ::MyVector{Int64}, ::UnitRange{Int64}, ::UnitRange{Int64}, ::Int64, ::Int64, ::Int64) at ./arrayshow.jl:67
 [7] print_matrix(::IOContext{REPL.Terminals.TTYTerminal}, ::MyVector{Int64}, ::String, ::String, ::String, ::String, ::String, ::String, ::Int64, ::Int64) at ./arrayshow.jl:186
 [8] print_matrix at ./arrayshow.jl:159 [inlined]
 [9] print_array at ./arrayshow.jl:308 [inlined]
 [10] show(::IOContext{REPL.Terminals.TTYTerminal}, ::MIME{Symbol("text/plain")}, ::MyVector{Int64}) at ./arrayshow.jl:345
 [11] display(::REPL.REPLDisplay, ::MIME{Symbol("text/plain")}, ::Any) at /Users/mason/julia/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:132
 [12] display(::REPL.REPLDisplay, ::Any) at /Users/mason/julia/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:136
 [13] display(::Any) at ./multimedia.jl:323
 ...

嗯,现在它要getindex

julia> Base.getindex(v::MyVector, args...) = getindex(v.v, args...)

julia> MyVector([1, 2, 3])
3-element MyVector{Int64}:
 1
 2
 3

什么?那不是我告诉它的打印格式!这是怎么回事?

【问题讨论】:

  • 您需要添加的方法记录在文档中(有很多示例等)作为官方 AbstractArray 接口:docs.julialang.org/en/latest/manual/interfaces/…
  • 我知道,但这实际上与问题无关。问题是关于如何为数组执行我自己的show 方法。我只是认为以这种格式发布问题会有所帮助,因为这是我多次经历的过程,但我已经看到其他人这样做了。
  • 没关系。但也可以让人们知道他们可以阅读文档。

标签: julia


【解决方案1】:

问题在于,在 julia 中,Base 定义了一个方法 Base.show(io::IO ::MIME"text/plain", X::AbstractArray),对于 display,它实际上比 Base.show(io::IO, v::MyVector) 更具体。 This section of the julia manual describes the sort of custom printing that AbstractArray uses。所以如果我们想使用我们自定义的show 方法,我们需要这样做

julia> function Base.show(io::IO, ::MIME"text/plain", v::MyVector{T}) where {T}
           println(io, "My custom vector with eltype $T and elements")
           for i in eachindex(v)
               println(io, "  ", v.v[i])
           end
       end

julia> MyVector([1, 2, 3])
My custom vector with eltype Int64 and elements
  1
  2
  3

另见:https://discourse.julialang.org/t/extending-base-show-for-array-of-types/31289

【讨论】:

    猜你喜欢
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多