【问题标题】:Getting UndefVarError: new not defined when trying to define a struct with an inner constructor in Julia获取 UndefVarError:尝试在 Julia 中使用内部构造函数定义结构时未定义新的
【发布时间】:2021-01-08 21:18:50
【问题描述】:

我是 Julia 的新手,正在尝试从 this article 复制的一些代码。它应该是在 Julia 中进行面向对象编程(即类)的一种方式:

using Lathe.stats: mean, std

struct NormalDistribution{P}
    mu::Float64
    sigma::Float64
    pdf::P
end

function NormalDistribution(x::Array)
        pdf(xt::Array) = [i = (i-μ) / σ for i in xt]
        return new{typeof(pdf)}(mean(x), std(x), pdf)
end

x = [5, 10, 15, 20]
dist = NormalDistribution(x)

但是,当我在 Jupiter 笔记本中使用 Julia 1.1.1 运行此程序时,会出现以下异常:

UndefVarError: new not defined

Stacktrace:
 [1] NormalDistribution(::Array{Int64,1}) at ./In[1]:11
 [2] top-level scope at In[1]:15

我在内部构造方法中找到了this documentation page,它解释了它们有

一个名为new 的特殊本地存在函数,用于创建块类型的对象。

(尽管上面链接的new 的文档说它是一个关键字)。

我可能复制了错误的代码,但也许有人可以解释如何实现原作者在文章中提出的内容。另外,我还不知道如何在 Julia 中进行调试,所以任何指针表示赞赏。

【问题讨论】:

    标签: oop constructor julia


    【解决方案1】:

    内部构造函数必须在结构体定义体中定义;这是new 唯一有特殊含义的地方。您的构造函数方法位于结构定义之外,其中 new 只是一个常规(未定义)名称。

    【讨论】:

      【解决方案2】:

      documentation page you linked to 的意思是 new 关键字只存在于 inner 构造函数中(相对于 outer 构造函数)。

      所以要么你选择一个外部构造函数,在这种情况下你想使用默认构造函数来实际创建你的新实例:

      using Statistics
      
      # First the type declaration, which comes with a default constructor
      struct NormalDistribution{P}
          mu::Float64
          sigma::Float64
          pdf::P
      end
      
      # Another outer constructor
      function NormalDistribution(x::Array)
          μ = mean(x)
          σ = std(x)
          pdf(xt::Array) = [(i-μ) / σ for i in xt]
      
          # This is a call to the constructor that was created for you by default
          return NormalDistribution(μ, σ, pdf)
      end
      
      julia> x = [5, 10, 15, 20]
      4-element Array{Int64,1}:
        5
       10
       15
       20
      
      julia> dist = NormalDistribution(x)
      NormalDistribution{var"#pdf#2"{Float64,Float64}}(12.5, 6.454972243679028, var"#pdf#2"{Float64,Float64}(12.5, 6.454972243679028))
      
      julia> dist.pdf([1, 2, 3])
      3-element Array{Float64,1}:
       -1.781572339255412
       -1.626653005407115
       -1.4717336715588185
      

      注意,原文章中pdf的定义显然是有问题的(如果只是因为没有定义μ和σ)。我试图修改它以使其有意义

      一个可能的问题是任何人都可以定义一个状态不一致的NormalDistribution 实例:

      julia> NormalDistribution(0., 1., x->x+1)
      NormalDistribution{var"#11#12"}(0.0, 1.0, var"#11#12"())
      

      这就是您可能想要实际定义内部构造函数的原因,在这种情况下,Julia 不会为您提供默认构造函数,但您可以访问该特殊的 new 函数,该函数会创建您正在定义的类型的对象:

      # A type declaration with an inner constructor
      struct NormalDistribution2{P}
          mu::Float64
          sigma::Float64
          pdf::P
      
          # The inner constructor is defined inside the type declaration block
          function NormalDistribution2(x::Array)
              μ = mean(x)
              σ = std(x)
              pdf(xt::Array) = [(i-μ) / σ for i in xt]
      
              # Use the `new` function to actually create the object
              return new{typeof(pdf)}(μ, σ, pdf)
          end
      end
      

      它的行为方式与带有外部构造函数的结构完全相同,只是这次不再提供默认构造函数:

      julia> dist2 = NormalDistribution2(x)
      NormalDistribution2{var"#pdf#5"{Float64,Float64}}(12.5, 6.454972243679028, var"#pdf#5"{Float64,Float64}(12.5, 6.454972243679028))
      
      julia> dist2.pdf([1, 2, 3])
      3-element Array{Float64,1}:
       -1.781572339255412
       -1.626653005407115
       -1.4717336715588185
      
      # No default constructor provided
      julia> NormalDistribution2(0., 1., x->x+1)
      ERROR: MethodError: no method matching NormalDistribution2(::Float64, ::Float64, ::var"#9#10")
      Stacktrace:
       [1] top-level scope at REPL[13]:1
      

      【讨论】:

      • 谢谢,这很好地解释了它。原始文章中代码的缩进是错误的,所以我的 NormalDistribution 函数最终在外部范围内,而不是在结构内。我已经要求他更正缩进。他似乎也错过了您所包含的μ = ..σ = .. 声明。
      【解决方案3】:

      好的。看起来你很困惑。因此,该函数意味着在结束之前作为外部构造函数的内部构造函数包含在内。问题是代码在文章中被缓慢地划分和构建,其中只显示了整个构造函数的一部分。如果您有兴趣,并且喜欢我的博客,我将在我的频道https://youtube.com/playlist?list=PLCXbkShHt01seTlnlVg6O7f6jKGTguFi7 上发布有关外部构造函数和内部构造函数的视频,这将是第 9 部分(我现在正在编辑它,)也许以视频形式观看会让它更有意义。 enter image description here

      【讨论】:

      • 我现在明白了,但为了避免进一步混淆,我认为如果你在文章中缩进内部构造函数会更好,这样更明显的是它在结构声明中。最后可能还会显示完整的可执行脚本。谢谢。
      • 同意后面的内部构造函数定义在结构之外的事实有点令人困惑。上面的评论可能会有所帮助。
      猜你喜欢
      • 2019-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多