Julia 当我们有这么多结构时,如何定义多个分派?
如果我们有一些结构,那么使用多个分派不是问题。 但是当我们有这么多结构时,如何使用多重分派呢? 例如,我们有如下N个结构:Julia 当我们有这么多结构时,如何定义多个分派?,julia,Julia,如果我们有一些结构,那么使用多个分派不是问题。 但是当我们有这么多结构时,如何使用多重分派呢? 例如,我们有如下N个结构: struct An a::Float64 end 还有一个函数,比如: f!(a::Ai) = exp(Ai.a) 当N很大时,它会让人头痛。 考虑到这个函数是简单和容易的!一个函数可以这么大 您可以在循环中枚举结构的名称,并使用@eval为每个结构生成和计算代码: julia> for S in [:A1, :A2, :A3] @ev
struct An
a::Float64
end
还有一个函数,比如:
f!(a::Ai) = exp(Ai.a)
当N很大时,它会让人头痛。
考虑到这个函数是简单和容易的!一个函数可以这么大 您可以在循环中枚举结构的名称,并使用@eval为每个结构生成和计算代码:
julia> for S in [:A1, :A2, :A3]
@eval begin
struct $S
a::Float64
end
f(x::$S) = exp(x.a)
end
end
julia> A2(2)
A2(2.0)
julia> f(A2(2))
7.38905609893065
这里我在同一个地方定义了结构,因为我在控制台中进行了尝试
但可能有更好的替代方案。eval通常被认为是次优设计的标志。您可以在循环中枚举结构的名称,并使用@eval为每个结构生成和计算代码:
julia> for S in [:A1, :A2, :A3]
@eval begin
struct $S
a::Float64
end
f(x::$S) = exp(x.a)
end
end
julia> A2(2)
A2(2.0)
julia> f(A2(2))
7.38905609893065
这里我在同一个地方定义了结构,因为我在控制台中进行了尝试
但可能有更好的替代方案。eval通常被认为是次优设计的标志。如果所有结构的函数定义都相同,则可以将它们定义为某个抽象类型的具体类型,并且只保留一个在抽象类型上分派的函数:
julia> abstract type Allmystructs end
julia> struct A1 <: Allmystructs
a::Float64
end
julia> struct A2 <: Allmystructs
a::Float64
end
julia> f(A :: Allmystructs) = exp(A.a)
f (generic function with 1 method)
julia> test1 = A1(5)
A1(5.0)
julia> test2 = A2(8)
A2(8.0)
julia> f(test1)
148.4131591025766
julia> f(test2)
2980.9579870417283
当然,如果每种结构类型的函数定义不同,这可能不是您想要的。在这种情况下,元编程可以成为您的朋友
编辑:输入错误。如果所有结构的函数定义相同,则可以将它们定义为某个抽象类型的具体类型,并只保留一个在抽象类型上分派的函数:
julia> abstract type Allmystructs end
julia> struct A1 <: Allmystructs
a::Float64
end
julia> struct A2 <: Allmystructs
a::Float64
end
julia> f(A :: Allmystructs) = exp(A.a)
f (generic function with 1 method)
julia> test1 = A1(5)
A1(5.0)
julia> test2 = A2(8)
A2(8.0)
julia> f(test1)
148.4131591025766
julia> f(test2)
2980.9579870417283
当然,如果每种结构类型的函数定义不同,这可能不是您想要的。在这种情况下,元编程可以成为您的朋友
编辑:输入错误。通常当代码有许多非常相似的结构时,这表明这可能是另一种选择 例如,假设我们有一个带有许多不同结构的彩色几何形状库:
const Point = Tuple{Float64, Float64}
struct Disc
center::Point
radius::Float64
red::Float64
green::Float64
blue::Float64
end
struct Rectangle
topleft::Point
bottomright::Point
red::Float64
green::Float64
blue::Float64
end
# ... etc., e.g. Triangle, Hexagon
现在假设我们想引入一个亮度函数,它返回形状颜色的感知亮度。一种方法是为每个结构定义一个方法,但由于这些方法都是相同的,我们也可以这样做:
const Shape = Union{Disc, Rectangle, Triangle, Hexagon}
luminance(shape::Shape) = 0.299*shape.red + 0.587*shape.green + 0.114*shape.blue)
这仍然有点烦人,因为我们需要在一个地方列出所有可用的形状。添加新形状会很麻烦。因此,实际上,我们可以制作一个抽象类型的形状结束,并让每个形状子类型结束,正如公认答案中所建议的那样。但在许多方面,这种方法仍然不能令人满意,因为它限制了所有未来形状共享相同的布局
解决此问题的更好方法是解耦所有彩色形状共享的红色、绿色和蓝色属性。因此,我们引入类型层次结构,如下所示:
const Point = Tuple{Float64, Float64}
struct Color
red::Float64
green::Float64
blue::Float64
end
abstract type Figure end
struct Disc <: Figure
center::Point
radius::Float64
end
struct Rectangle <: Figure
topleft::Point
bottomright::Point
end
struct ColoredShape{F <: Figure}
figure::F
color::Color
end
现在,我们不再使用矩形0.0,0.0,1.0,1.0,0.5,0.5,0.5来表示灰色矩形,而是使用彩色ShapeRectange0.0,0.0,1.0,1.0,Color0.5,0.5,0.5。与定义多个相同的亮度方法不同,我们只为颜色结构定义一次。您还可以(可选)为ColoredShape定义另一个委托给属性颜色的方法,但这只是一个附加方法,而不是N!此模式还允许我们为颜色定义的功能在其他上下文(除了彩色形状)中重用
一般来说,最好将概念分解为最小的可消化部分,以实现可重用性和可理解性。如果有很多非常相似的结构,那么为所有结构定义函数似乎是件苦差事,这就意味着可能有一些共享功能需要考虑。通常当代码有很多非常相似的结构时,这就意味着可能是另一种选择 例如,假设我们有一个带有许多不同结构的彩色几何形状库:
const Point = Tuple{Float64, Float64}
struct Disc
center::Point
radius::Float64
red::Float64
green::Float64
blue::Float64
end
struct Rectangle
topleft::Point
bottomright::Point
red::Float64
green::Float64
blue::Float64
end
# ... etc., e.g. Triangle, Hexagon
现在假设我们想引入一个亮度函数,它返回形状颜色的感知亮度。一种方法是为每个结构定义一个方法,但由于这些方法都是相同的,我们也可以这样做:
const Shape = Union{Disc, Rectangle, Triangle, Hexagon}
luminance(shape::Shape) = 0.299*shape.red + 0.587*shape.green + 0.114*shape.blue)
这仍然有点烦人,因为我们需要在一个地方列出所有可用的形状。添加新形状会很麻烦。因此,实际上,我们可以制作一个抽象类型的形状结束,并让每个形状子类型结束,正如公认答案中所建议的那样。但在许多方面,这种方法仍然不能令人满意,因为它限制了所有未来形状共享相同的布局
解决此问题的更好方法是解耦所有彩色形状共享的红色、绿色和蓝色属性。因此,我们引入类型层次结构,如下所示:
const Point = Tuple{Float64, Float64}
struct Color
red::Float64
green::Float64
blue::Float64
end
abstract type Figure end
struct Disc <: Figure
center::Point
radius::Float64
end
struct Rectangle <: Figure
topleft::Point
bottomright::Point
end
struct ColoredShape{F <: Figure}
figure::F
color::Color
end
现在,我们不再使用矩形0.0,0.0,1.0,1.0,0.5,0.5,0.5来表示灰色矩形,而是使用彩色ShapeRectange0.0,0.0,1.0,1.0,Color0.5,0.5,0.5。与定义多个相同的亮度方法不同,我们将
d仅为颜色结构定义一次。您还可以(可选)为ColoredShape定义另一个委托给属性颜色的方法,但这只是一个附加方法,而不是N!此模式还允许我们为颜色定义的功能在其他上下文(除了彩色形状)中重用
一般来说,最好将概念分解为最小的可消化部分,以实现可重用性和可理解性。如果有很多非常相似的结构,那么为所有结构定义函数似乎都是件麻烦事,这表明可能有一些共享功能需要考虑。是否有必要在同一个循环中同时定义函数和结构?不,没有必要。是否有必要在同一个循环中同时定义函数和结构?不,没有必要。这是一个比使用eval更好的解决方案!这是一个很好的解决方案,但应该指出,一般来说,抽象类型应该用于概念相同但结构不同的事物,而不是结构相同的事物。参数化类型或组合可能是更好的选择。这是比使用eval更好的解决方案!这是一个很好的解决方案,但应该指出,一般来说,抽象类型应该用于概念相同但结构不同的事物,而不是结构相同的事物。参数化类型或组合可能是更好的选择。如果你有很多几乎相同的结构,并且做几乎相同的事情,也许你不需要它们全部?为什么有很多非常相似的结构?可以改用参数化类型吗?如果你有大的函数,你能把普通的代码分离出来,而不是为每一种类型重新编写整个代码吗?如果你有很多几乎相同的结构,做几乎相同的事情,也许你不需要它们全部?为什么有很多非常相似的结构?可以改用参数化类型吗?如果你有大型函数,你能把普通代码分离出来,而不是为每种类型重新编写整个代码吗?