构造函数
构造函数是用来创建新对象的函数 – 确切地说,它创建的是复合类型的实例。在 Julia 中,类型对象也同时充当构造函数的角色:可以用类名加参数元组的方式像函数调用一样来创建新实例。

对很多类型来说,通过给所有成员赋值来创建新对象的这种方式就足以用于产生新实例了。然而,在某些情形下,创建复合对象需要更多的功能。有时必须通过检查或转化参数来确保固有属性不变。递归数据结构,特别是那些可能引用自身的数据结构,它们通常不能被干净地构造,而是需要首先被不完整地构造,然后再通过编程的方式完成补全。为了方便,有时需要用较少的参数或者不同类型的参数来创建对象,Julia 的对象构造系统解决了所有这些问题。
外部构造方法
构造函数与 Julia 中的其他任何函数一样,其整体行为由其各个方法的组合行为定义。因此,只要定义新方法就可以向构造函数添加功能。例如,假设你想为 Foo 对象添加一个构造方法,该方法只接受一个参数并其作为 bar 和 baz 的值。同样,也可以为 Foo 添加新的零参数构造方法,它为 bar 和 baz 提供默认值。

上图中的零参数构造方法会调用单参数构造方法,单参数构造方法又调用了自动提供默认值的双参数构造方法。上面附加的这类构造方法,它们的声明方式与普通的方法一样,像这样的构造方法被称为外部构造方法,下文很快就会揭示这样称呼的原因。外部构造方法只能通过调用其他构造方法来创建新实例,比如自动提供默认值的构造方法。
内部构造方法
尽管外部构造方法成功地为构造对象提供了额外的便利,但它无法解决另外两个在前面提到的问题:确保固有属性不变和允许创建自引用对象。因此,我们需要内部构造方法。内部构造方法和外部构造方法很相像,但有两点不同:
- 内部构造方法在 struct-block 的内部声明,而不是和普通方法一样在外部。
- 内部构造方法能够访问一个特殊的局部函数 new,此函数能够创建该类型的对象。
例如,假设我们要声明一个保存一对实数的类型,但要约束第一个数不大于第二个数。

如上图所示, OrderedPair 对象只能在 x <= y 时被成功构造。
如果类型被声明为 mutable,我们可以直接更改成员变量的值来打破这个固有属性,然而,在未经允许的情况下,随意摆弄对象的内核一般都是不好的行为。我们可以在以后任何时候提供额外的外部构造方法,但一旦类型被声明了,就没有办法来添加更多的内部构造方法了。由于外部构造方法只能通过调用其它的构造方法来创建对象,所以最终构造对象的一定是某个内部构造函数。这保证了类型的对象必须是经过内部构造才得已存在,从而在某种程度上保证了类型的固有属性。
只要定义了任何一个内部构造方法,Julia 就不会再提供默认的构造方法:它会假定你已经为自己提供了所需的所有内部构造方法。默认构造方法等效于一个你自己编写的内部构造函数,该函数将所有成员作为参数(如果相应的成员具有类型,则约束为正确的类型),并将它们传递给 new,最后返回结果对象。
julia> struct Foo bar baz Foo(bar,baz) = new(bar,baz) end
这个声明与前面没有显式内部构造方法的 Foo 类型的定义效果相同。 以下两个类型是等价的 – 一个具有默认构造方法,另一个具有显式构造方法。

提供尽可能少的内部构造方法是一种良好的形式:仅在需要显式地处理所有参数,以及强制执行必要的错误检查和转换时候才使用内部构造。其它用于提供便利的构造方法,比如提供默认值或辅助转换,应该定义为外部构造函数,然后再通过调用内部构造函数来执行繁重的工作。这种解耦是很自然的。