Debugging eltype样式功能的Julia methoderror

Debugging eltype样式功能的Julia methoderror,debugging,julia,Debugging,Julia,我有一个抽象容器AbstractContainer在类型T上参数化,该类型指示容器中的内容的类型。然后,每个子类型(在本例中为FloatContainer)指定容器中的实际内容(在本例中为Float64) 理想情况下,如果我只有容器类型,我会有一种方法返回容器中的类型。 这样,我就可以在另一个结构中使用它(在本例中,MultiplyBy) 我想用与Julia的内部eltype函数类似的方法来实现它,但我无法让它工作。 我总是得到一个方法错误(有关详细的错误消息,请参阅最后一个代码段) 我必须承认

我有一个抽象容器
AbstractContainer
在类型
T
上参数化,该类型指示容器中的内容的类型。然后,每个子类型(在本例中为
FloatContainer
)指定容器中的实际内容(在本例中为
Float64

理想情况下,如果我只有容器类型,我会有一种方法返回容器中的类型。 这样,我就可以在另一个结构中使用它(在本例中,
MultiplyBy

我想用与Julia的内部
eltype
函数类似的方法来实现它,但我无法让它工作。 我总是得到一个方法错误(有关详细的错误消息,请参阅最后一个代码段)

我必须承认我对朱莉娅很陌生,但我很想了解更多。 因此,无论是关于如何以不同方式解决此问题,还是关于我的错误所在,我们都非常感谢您提供的任何提示。

确定元素类型 您的
gettype
不起作用,因为它分派抽象类型,但您的容器对象都将具有具体类型。您必须使用才能正确分派

比较抽象类型上的分派:

julia> eltype1(::Type{AbstractContainer{T}}) where T = T
eltype1 (generic function with 1 method)

julia> eltype1(FloatContainer)
ERROR: MethodError: no method matching eltype1(::Type{FloatContainer})
Closest candidates are:
  eltype1(::Type{AbstractContainer{T}}) where T at REPL[4]:1
Stacktrace:
 [1] top-level scope at REPL[5]:1

julia> eltype1(AbstractContainer{Float64})
Float64
julia> eltype2(::Type{<:AbstractContainer{T}}) where T = T
eltype2 (generic function with 1 method)

julia> eltype2(FloatContainer)
Float64

julia> eltype2(AbstractContainer{Float64})
Float64
通过对抽象类型的子类型进行分派:

julia> eltype1(::Type{AbstractContainer{T}}) where T = T
eltype1 (generic function with 1 method)

julia> eltype1(FloatContainer)
ERROR: MethodError: no method matching eltype1(::Type{FloatContainer})
Closest candidates are:
  eltype1(::Type{AbstractContainer{T}}) where T at REPL[4]:1
Stacktrace:
 [1] top-level scope at REPL[5]:1

julia> eltype1(AbstractContainer{Float64})
Float64
julia> eltype2(::Type{<:AbstractContainer{T}}) where T = T
eltype2 (generic function with 1 method)

julia> eltype2(FloatContainer)
Float64

julia> eltype2(AbstractContainer{Float64})
Float64

我不确定您需要什么,但我用您的结构编写了一个工作示例:

abstract type AbstractContainer{T} end

#not necessary anymore
#gettype(a::Type{AbstractContainer{T}})  where T = T

struct FloatContainer{T<:AbstractFloat} <: AbstractContainer{T} #AbstractFloat, to include Float32, BigFloats and others
  x::T
end

 #you can't use functions on struct definitions, if you need more restrictions,
 #use a Constructor
struct MultiplyBy{T<:AbstractContainer}
  x::T
end

#example external Constructor

MultiplyBy(x::AbstractFloat) = MultiplyBy(FloatContainer(x))

value(x::AbstractContainer) = x.x #basic accesor function
value(x::MultiplyBy) = value(x.x) 

function process(m::MultiplyBy, v::AbstractContainer)
  return typeof(v)(value(m)*value(v)) #calling accesor functions to access the values.
end

function main()
  x = FloatContainer(2.0)

  y = FloatContainer(3.0)
  op = MultiplyBy(y) #the parametric type is inferred automatically, no need to use Curly Braces

  z = process(op, x)
  println(value(x)) #better use accesor functions that direct access, as the underlying implementation can change
end

main()
抽象类型抽象容器{T}end
#不再需要了
#gettype(a::Type{AbstractContainer{T}}),其中T=T

struct FloatContainer{tw为什么要使用子类型而不是只使用顶级类的type参数来指示容器中的内容?
abstract type AbstractContainer{T} end

#not necessary anymore
#gettype(a::Type{AbstractContainer{T}})  where T = T

struct FloatContainer{T<:AbstractFloat} <: AbstractContainer{T} #AbstractFloat, to include Float32, BigFloats and others
  x::T
end

 #you can't use functions on struct definitions, if you need more restrictions,
 #use a Constructor
struct MultiplyBy{T<:AbstractContainer}
  x::T
end

#example external Constructor

MultiplyBy(x::AbstractFloat) = MultiplyBy(FloatContainer(x))

value(x::AbstractContainer) = x.x #basic accesor function
value(x::MultiplyBy) = value(x.x) 

function process(m::MultiplyBy, v::AbstractContainer)
  return typeof(v)(value(m)*value(v)) #calling accesor functions to access the values.
end

function main()
  x = FloatContainer(2.0)

  y = FloatContainer(3.0)
  op = MultiplyBy(y) #the parametric type is inferred automatically, no need to use Curly Braces

  z = process(op, x)
  println(value(x)) #better use accesor functions that direct access, as the underlying implementation can change
end

main()