mut Function
A struct is a value type whose instance member functions cannot modify the instance. In the following example, the value of the member variable i
cannot be changed by the member function g
:
struct Foo {
var i = 0
public func g() {
i += 1 // Error, the value of an instance member variable cannot be modified in an instance member function
}
}
The mut function is a special instance member function that can modify the struct
instance. In the mut
function, this
contains special semantics that allows it to modify fields in place.
Note:
The
mut
function can be defined only in an interface, struct, and struct extension. (A class is a reference type. Instance member functions can modify instance member variables without addingmut
. Therefore, themut
function cannot be defined in a class.)
Definition
Compared with common instance member functions, the mut function has an additional modifier mut
.
In the following example, the mut
modifier is added before the g
function, which allows the value of the member variable i
to be changed in the function body:
struct Foo {
var i = 0
public mut func g() {
i += 1 // Ok
}
}
mut
can be used to modify instance member functions only.
struct A {
public mut func f(): Unit {} // Ok
public mut operator func +(rhs: A): A { // Ok
A()
}
public mut static func g(): Unit {} // Error, static member functions cannot be modified with 'mut'
}
this
in the mut function cannot be captured or used as an expression. The instance member variables of a struct cannot be captured in the mut
function.
Example:
struct Foo {
var i = 0
public mut func f(): Foo {
let f1 = { => this } // Error, 'this' in mut functions cannot be captured
let f2 = { => this.i = 2 } // Error, instance member variables in mut functions cannot be captured
let f3 = { => this.i } // Error, instance member variables in mut functions cannot be captured
let f4 = { => i } // Error, instance member variables in mut functions cannot be captured
this // Error, 'this' in mut functions cannot be used as expressions
}
}
mut Function in Interfaces
Instance member functions in interfaces can also be modified by mut
.
The struct
type must be modified by the same mut
modifier when implementing an interface
function. When a type other than struct
implements an interface
function, the mut
modifier cannot be used.
Example:
interface I {
mut func f1(): Unit
func f2(): Unit
}
struct A <: I {
public mut func f1(): Unit {} // Ok: as in the interface, the 'mut' modifier is used
public func f2(): Unit {} // Ok: as in the interface, the 'mut' modifier is not used
}
struct B <: I {
public func f1(): Unit {} // Error, 'f1' is modified with 'mut' in interface, but not in struct
public mut func f2(): Unit {} // Error, 'f2' is not modified with 'mut' in interface, but did in struct
}
class C <: I {
public func f1(): Unit {} // Ok
public func f2(): Unit {} // Ok
}
When a struct
instance is assigned to an interface
type, the copy semantics is used. Therefore, the mut
function of the interface
cannot change the value of the struct
instance.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
public var v = 0
public mut func f(): Unit {
v += 1
}
}
main() {
var a = Foo()
var b: I = a
b.f() // Calling 'f' via 'b' cannot modify the value of 'a'
println(a.v) // 0
}
The program output is as follows:
0
Constraints on the mut Function
Since a struct
is a value type, if a variable of the struct
type is declared using let
, the mut
function of this type cannot be accessed through this variable.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
public var i = 0
public mut func f(): Unit {
i += 1
}
}
main() {
let a = Foo()
a.f() // Error, 'a' is of type struct and is declared with 'let', the 'mut' function cannot be accessed via 'a'
var b = Foo()
b.f() // Ok
let c: I = Foo()
c.f() // Ok
}
To avoid escape, if the type of a variable is struct
, the variable cannot use functions modified by mut
as the first-class citizens, but it can still call these mut
functions.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
var i = 0
public mut func f(): Unit {
i += 1
}
}
main() {
var a = Foo()
var fn = a.f // Error, mut function 'f' of 'a' cannot be used as a first class citizen.
var b: I = Foo()
fn = b.f // Ok
}
To avoid escape, non-mut
instance member functions (including lambda
expressions) cannot directly access mut
functions of the corresponding type, while the reverse is allowed.
Example:
struct Foo {
var i = 0
public mut func f(): Unit {
i += 1
g() // Ok
}
public func g(): Unit {
f() // Error, mut functions cannot be invoked in non-mut functions
}
}
interface I {
mut func f(): Unit {
g() // Ok
}
func g(): Unit {
f() // Error, mut functions cannot be invoked in non-mut functions
}
}