最近使用了 * 法广播来扩展一个结构体的算子,正常两个放在一起没问题,但是与其他广播混合使用却出现了问题,如下是最小问题复现:
mutable struct NamedArray
data::Array
name::String
function NamedArray(x, name)
new(x, name)
end
end
function Base.Broadcast.broadcasted(::typeof(*), x::Array, y::NamedArray)
return NamedArray(x .* y.data, y.name)
end
然后 [4 3 2 1] .* NamedArray([1 2 3 4], "julia")
可以出正确的结果,但是
([5 4 3 2] .- 1) .* NamedArray([1 2 3 4],"julia")
就会报错
ERROR: MethodError: no method matching length(::NamedArray)
Closest candidates are:
length(::Union{Base.KeySet, Base.ValueIterator}) at D:\julia-1.7.2-win64\share\julia\base\abstractdict.jl:58
length(::Union{LinearAlgebra.Adjoint{T, S}, LinearAlgebra.Transpose{T, S}} where {T, S}) at D:\julia-1.7.2-win64\share\julia\stdlib\v1.7\LinearAlgebra\src\adjtrans.jl:171
length(::Base.Unicode.GraphemeIterator{S}) where S at D:\julia-1.7.2-win64\share\julia\base\strings\unicode.jl:664
然后加了
Base.length(x::NamedArray) = length(x.data)
求长度方法后又报错
julia> ([5 4 3 2] .- 1) .* NamedArray([1 2 3 4], "julia")
ERROR: MethodError: no method matching iterate(::NamedArray)
Closest candidates are:
iterate(::Union{LinRange, StepRangeLen}) at D:\julia-1.7.2-win64\share\julia\base\range.jl:826
iterate(::Union{LinRange, StepRangeLen}, ::Integer) at D:\julia-1.7.2-win64\share\julia\base\range.jl:826
iterate(::T) where T<:Union{Base.KeySet{<:Any, <:Dict}, Base.ValueIterator{<:Dict}} at D:\julia-1.7.2-win64\share\julia\base\dict.jl:695
然后再创建个迭代方法还是不对…
julia> Base.iterate(s::NamedArray, i::Integer=1) = i>length(s.data) ? nothing : (s.data[i],i+1)
julia> ([5 4 3 2] .- 1) .* NamedArray([1 2 3 4], "julia")
4×4 Matrix{Int64}:
4 3 2 1
8 6 4 2
12 9 6 3
16 12 8 4
按照我的理解,应该是先求出 ([5 4 3 2] .- 1)
再计算其与 NamedArray([1 2 3 4], "julia")
的点乘,就像下边的就是对的
julia> begin
a = [5 4 3 2] .- 1;
b = NamedArray([1 2 3 4], "julia");
a .* b
end
NamedArray([4 6 6 4], "julia")
同时,原生的 Julia 数组也是可以的
julia> (1 .- randn(1,3)) .* randn(2,3)
2×3 Matrix{Float64}:
-0.566199 1.13881 1.47938
0.243334 -1.59071 -0.38588
有懂的同学麻烦帮个忙,谢谢啦 ::