Defining a struct Type
The definition of a struct
type starts with the keyword struct
, followed by the struct
name and the struct
definition body defined in braces. The struct
definition body can define a series of member variables, member properties (see Properties), static initializers, constructors, and member functions.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
The preceding example defines a struct
type named Rectangle
. It has two member variables width
and height
of the Int64
type, a constructor with two parameters of the Int64
type (with the constructor defined by the keyword init
, and the member variables initialized in the function body), as well as a member function area
(returning the product of width
and height
).
Note:
struct
can be defined only on top of a source file.
struct Member Variables
struct
member variables can be grouped into instance member variables and static member variables (modified by static
modifiers and must have initial values). The difference lies in that instance member variables can be accessed only through struct
instances (If a
is an instance of the T
type, a
is a value of the T
type), whereas static member variables can be accessed only through the struct
type names.
When you define instance member variables, you are not required to set initial values but must specify the types, such as width
and height
in the preceding example. However, you can also set initial values as follows:
struct Rectangle {
let width = 10
let height = 20
}
struct Static Initializers
struct
allows you to define a static initializer and initialize static member variables with assignment expressions in the static initializer.
A static initializer starts with static init
, followed by a parameter list without parameters and a function body. It cannot be modified by an access modifier. All static member variables must be initialized in the function body. Otherwise, an error is reported during compilation.
struct Rectangle {
static let degree: Int64
static init() {
degree = 180
}
}
A struct
defines a maximum of one static initializer. In other cases, a redefinition error is reported.
struct Rectangle {
static let degree: Int64
static init() {
degree = 180
}
static init() { // Error, redefinition with the previous static init function
degree = 180
}
}
struct Constructors
struct
supports two types of constructors: common constructors and primary constructors.
A common constructor starts with the keyword init
, followed by the parameter list and function body. All instance member variables must be initialized in the function body. Otherwise, an error is reported during compilation. If a member variable name cannot be distinguished from a parameter name, you can add this
before the member variable name to indicate the current instance of the struct
.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) { // Error, 'height' is not initialized in the constructor
this.width = width
}
}
A struct
can define multiple common constructors, but they must be overloaded (see Function Overloading). Otherwise, a redefinition error is reported.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64) {
this.width = width
this.height = width
}
public init(width: Int64, height: Int64) { // Ok: overloading with the first init function
this.width = width
this.height = height
}
public init(height: Int64) { // Error, redefinition with the first init function
this.width = height
this.height = height
}
}
In addition to defining several common constructors named init
, a struct
can also define a maximum of one primary constructor. The primary constructor has the same name as the struct
type. The parameter list of the primary constructor can contain two types of parameters: common parameters and member variable parameters (with let
or var
added before the parameter names). Member variable parameters define member variables and constructor parameters.
The definition of a struct
can be simplified by using a primary constructor. For example, the Rectangle
struct that contains an init
constructor can be simplified as follows:
struct Rectangle {
public Rectangle(let width: Int64, let height: Int64) {}
}
Common parameters can also be defined in the parameter list of a primary constructor. For example:
struct Rectangle {
public Rectangle(name: String, let width: Int64, let height: Int64) {}
}
If the definition of a struct
does not contain a custom constructor (including the primary constructor) and all instance member variables have initial values, a parameterless constructor is automatically generated (Calling the parameterless constructor creates an object whose instance member variable values equal to their initial values). Otherwise, the parameterless constructor is not automatically generated. The following struct
definition displays an automatically generated parameterless constructor:
struct Rectangle {
let width: Int64 = 10
let height: Int64 = 10
/* Auto-generated memberwise constructor:
public init() {
}
*/
}
struct Member Functions
struct
member functions are classified into instance member functions and static member functions (modified by the static
modifier). The difference lies in that the former can be accessed only through struct
instances, whereas the latter can be accessed only through struct
type names. Static member functions cannot access instance member variables or call instance member functions. In contrast, instance member functions can access static member variables and static member functions.
In the following example, area
and typeName
are an instance member function and a static member function, respectively.
struct Rectangle {
let width: Int64 = 10
let height: Int64 = 20
public func area() {
this.width * this.height
}
public static func typeName(): String {
"Rectangle"
}
}
An instance member function can access its member variables through this
. For example:
struct Rectangle {
let width: Int64 = 1
let height: Int64 = 1
public func area() {
this.width * this.height
}
}
Access Modifiers of a struct Member
The members of a struct
(including member variables, member properties, constructors, member functions, and operator functions (see Operator Overloading)) are modified by four access modifiers: private
, internal
(default), protected
, and public
.
private
: A member is visible only in a definedstruct
.internal
: A member is visible only in a package and its subpackages (including all nested subpackages). For details, see Package.protected
: A member is visible only in a module. For details, see Package.public
: A member is visible both inside and outside the module.
In the following example, width
is modified by public
and can be accessed outside the class. height
is modified by the default access modifier and is visible only in the package and its subpackages.
package a
public struct Rectangle {
public var width: Int64
var height: Int64
private var area: Int64
...
}
func samePkgFunc() {
var r = Rectangle(10, 20)
r.width = 8 // Ok: public 'width' can be accessed here
r.height = 24 // Ok: 'height' has no modifier and can be accessed here
r.area = 30 // Error, private 'area' can't be accessed here
}
package b
import a.*
main() {
var r = Rectangle(10, 20)
r.width = 8 // Ok: public 'width' can be accessed here
r.height = 24 // Error, no modifier 'height' can't be accessed here
r.area = 30 // Error, private 'area' can't be accessed here
}
Disabling Recursive structs
Both recursive and mutually recursive structs
are invalid. For example:
struct R1 { // Error, 'R1' recursively references itself
let other: R1
}
struct R2 { // Error, 'R2' and 'R3' are mutually recursive
let other: R3
}
struct R3 { // Error, 'R2' and 'R3' are mutually recursive
let other: R2
}