Julia自定义参数化类型与构造器交互问题求助
类型定义
首先定义了两个参数化类型:
struct Monomial{T<:Number} coeff::T exp::Int end struct Poly{T<:Number} exprs::Vector{Monomial{T}} end
问题重现
执行以下代码时触发错误:
p = Poly([Monomial(1,2), Monomial(3,3)]) result = Monomial{<:Number}[] for expr in p.exprs push!(result, Monomial(expr.coeff, expr.exp)) end Poly(result)
抛出错误:
MethodError: no method matching Poly(::Vector{Monomial})
手动指定具体类型(如result=Monomial{Int64}[])可以修复,但在函数中希望有更简洁的写法,比如当前的differentiate函数:
function differentiate(p::Poly{<:Number}) p = simplify(p) currenttype = typeof((p.exprs[1]).coeff) result = Monomial{currenttype}[] for expr in p.exprs push!(result, Monomial(expr.coeff, expr.exp)) end Poly(result) end
问题原因
Poly{T}的构造器要求传入的数组必须是Vector{Monomial{T}},其中T是具体的Number子类型(比如Int64、Float64)。而Monomial{<:Number}[]创建的数组元素类型是Monomial(即未指定参数的UnionAll类型),并非某个具体的Monomial{T},因此类型不匹配,无法调用Poly的构造器。
简洁解决方案
方案1:利用Poly的类型参数T
在函数中直接通过p的类型参数获取T,无需手动提取元素类型:
function differentiate(p::Poly{T}) where T<:Number p = simplify(p) result = Monomial{T}[] for expr in p.exprs # 可在此加入求导逻辑,示例保留原代码逻辑 push!(result, Monomial(expr.coeff, expr.exp)) end Poly(result) end
T会自动绑定到输入p的具体类型参数,比如当p是Poly{Int64}时,result就是Vector{Monomial{Int64}},完全符合构造器要求。
方案2:使用similar创建同类型数组
如果需要基于原数组的类型创建新数组,可以用similar函数,它会自动继承原数组的元素类型:
function differentiate(p::Poly{<:Number}) p = simplify(p) result = similar(p.exprs, 0) # 创建空的同类型数组 for expr in p.exprs push!(result, Monomial(expr.coeff, expr.exp)) end Poly(result) end
similar(p.exprs, 0)会生成一个与p.exprs元素类型相同的空数组,避免手动指定类型参数。
方案3:扩展Poly的构造器(可选)
如果希望Poly能接受任意Vector{Monomial{S}}(S<:Number),可以扩展构造器:
Poly(exprs::Vector{Monomial{S}}) where S<:Number = Poly{S}(exprs)
不过原定义的Poly{T}已经隐含了这个构造逻辑,通常不需要额外扩展,但如果有特殊场景可以使用。
补充说明
空数组Monomial{<:Number}[]无法用于构造Poly,因为此时不存在具体的T类型参数,Poly的定义要求所有项的系数类型必须统一为某个具体的Number子类型,这是参数化类型的约束,确保类型一致性。
内容的提问来源于stack exchange,提问作者learningjulia83

