当前位置: 首页 > 知识库问答 >
问题:

内部构造器究竟是什么?

赵兴朝
2023-03-14
  1. 内部构造函数的准确定义是什么?在Julia-V0.6+中,“任何可以使用签名typename{...}(...)(注意{}部分)调用的构造函数都是内部构造函数”是正确的吗?
  2. 正如下面的注释中所讨论的,仅限于外部的构造函数实际上是显式内部构造函数吗?
  3. 使用方法检查方法是否是内部/外部构造函数是否正确?
  4. Julia自动定义的默认构造函数与用户显式定义的相应构造函数有什么不同?

顺便说一句,我知道如何使用以及何时使用内部构造函数。我知道什么是内部构造函数,直到只有外部构造函数进来,把水搅浑了。:(

让我们回忆一下Doc中的一些声明

构造函数就像Julia中的任何其他函数一样,它的整体行为是由其方法的组合行为定义的。

julia> struct Foo{T}
    x::T
end

julia> methods(Foo)
# 2 methods for generic function "(::Type)":
(::Type{Foo})(x::T) where T in Main at REPL[1]:2  # outer ctor  「1」
(::Type{T})(arg) where T in Base at sysimg.jl:24  # default convertion method「2」

julia> @which Foo{Int}(1) # or methods(Foo{Int})
(::Type{Foo{T}})(x) where T in Main at REPL[1]:2 # inner ctor 「3」

但是,仅限于外部的构造函数给构造函数的故事增加了另一个问题:

julia> struct SummedArray{T<:Number,S<:Number}
           data::Vector{T}
           sum::S
           function SummedArray(a::Vector{T}) where T
               S = widen(T)
               new{T,S}(a, sum(S, a))
           end
       end
julia> methods(SummedArray)
# 2 methods for generic function "(::Type)":
(::Type{SummedArray})(a::Array{T,1}) where T in Main at REPL[1]:5 # outer ctor「4」
(::Type{T})(arg) where T in Base at sysimg.jl:24

Hmm,类型声明块中的外部构造函数,它还调用new。我想这里的目的只是为了阻止Julia为我们定义默认的内部-外部构造函数对,但是文档中的第二个语句在这种情况下仍然是正确的吗?对新用户来说很困惑。

在这里,我读到了另一种形式的内部构造函数:

julia> struct Foo{T}
     x::T
     (::Type{Foo{T}})(x::T) = new{T}(x) 
   end

julia> methods(Foo)
# 1 method for generic function "(::Type)":
(::Type{T})(arg) where T in Base at sysimg.jl:24

julia> methods(Foo{Int})
# 2 methods for generic function "(::Type)":
(::Type{Foo{T}})(x::T) where T in Main at REPL[2]:3  「5」
(::Type{T})(arg) where T in Base at sysimg.jl:24

所以我的问题是内部构造函数的准确定义是什么?在Julia-V0.6+中,“任何可以用签名typeName{...}(...)(注意{}部分)调用的构造函数都是内部构造函数”是正确的吗?

共有1个答案

柳志专
2023-03-14

举个例子,假设您想定义一个表示偶数的类型:

julia> struct Even
          e::Int
       end

julia> Even(2)
Even(2)

到目前为止还不错,但是您还希望构造函数拒绝奇数,到目前为止even(x)不拒绝:

julia> Even(3)
Even(3)

因此,您尝试将自己的构造函数编写为

julia> Even(x) = iseven(x) ? Even(x) : throw(ArgumentError("x=$x is odd"))
Even
julia> Even(3)
Even(3)

为什么?让我们问问Julia她刚刚打了什么电话:

julia> @which Even(3)
Even(e::Int64) in Main at REPL[1]:2

这不是您定义的方法(查看参数名称和类型),这是隐式提供的构造函数。也许我们应该重新定义一下?好吧,不要在家里尝试这个:

julia> Even(e::Int) = iseven(e) ? Even(e) : throw(ArgumentError("e=$e is odd"))
Even
julia> Even(2)
ERROR: StackOverflowError:
Stacktrace:
 [1] Even(::Int64) at ./REPL[11]:0
 [2] Even(::Int64) at ./REPL[11]:1 (repeats 65497 times) 

我们刚刚创建了一个无限循环:我们重新定义了even(e)来递归地调用它自己。我们现在面临着一个既有鸡又有蛋的问题:我们想要重新定义隐式构造函数,但我们需要一些其他的构造函数来调用已定义的函数。正如我们所看到的,调用甚至(e)都不是可行的选择。

julia> struct Even
          e::Int
          Even(e::Int) = iseven(e) ? new(e) : throw(ArgumentError("e=$e is odd"))
       end


julia> Even(2)
Even(2)

julia> Even(3)
ERROR: ArgumentError: e=3 is odd
..

在内部构造函数中,可以使用new()语法调用原始隐式构造函数。外部构造函数不可用此语法。如果您尝试使用它,您将得到一个错误:

julia> Even() = new(2)
Even

julia> Even()
ERROR: UndefVarError: new not defined 
..
 类似资料:
  • 本文向大家介绍深入探究C++ string的内部究竟是什么样的,包括了深入探究C++ string的内部究竟是什么样的的使用技巧和注意事项,需要的朋友参考一下 在C语言中,有两种方式表示字符串: 一种是用字符数组来容纳字符串,例如char str[10] = "abc",这样的字符串是可读写的; 一种是使用字符串常量,例如char *str = "abc",这样的字符串只能读,不能写。 两种形式总

  • 问题内容: 设置或设置为弹性项目而不是设置之间有区别吗? 是属性的“转折点” 吗? 当我设置浏览器时,如何确定将项目下移到新行的哪一点?是根据他们的宽度还是“弹性基础”? 示例:最后两个框具有相同的功能,但是当窗口在300px至400px之间时, 只有 其中一个向下移动。为什么? 问题答案: 允许您在计算其他任何内容之前指定元素的初始/开始大小。它可以是百分比或绝对值。 但是,它 不是 弯曲增长/

  • 问题内容: 我在jquery图像滑块演示中找到了reset.css文件,但它从未包含在主index.html文件中。应该做什么,更重要的是,您将它放在哪里?你把它之前 任何引用的样式表()? 这是reset.css内部的代码 问题答案: 最初,关于样式的工作方式还没有标准化,每个浏览器都实现了自己认为正确的方式。您在IE中看到太多有关样式错误的问题的原因之一是,因为IE是样式方面与其他浏览器最不相

  • 问题内容: HashMap中的Hash Collision或Hashing Collision并不是一个新话题,我遇到了多个博客和讨论区,解释了如何产生Hash Collision或如何以模棱两可和详细的方式避免它。我最近在一次采访中遇到了这个问题。我有很多事情要解释,但我认为准确地给出正确的解释真的很困难。抱歉,如果我在这里重复我的问题,请给我准确的答案: 哈希冲突到底是什么?它是一项功能或常见

  • vsftp的配置参数有一项: 这个选项代表了一个目录,一个本地的(非匿名帐号)登陆vsftpd后,vsftpd就切入到其中。 还是不懂什么意思?

  • 问题内容: 我到处都是,找不到可靠的答案。根据文档,在以下情况下,Java引发java.lang.StackOverflowError错误: 由于应用程序递归过深而在堆栈溢出时抛出。 但这提出了两个问题: 不仅通过递归,还有其他方法可以使堆栈溢出吗? 是在JVM实际溢出堆栈之前还是之后发生StackOverflowError? 详细阐述第二个问题: 当Java引发StackOverflowErro