Skip to content

29-mut 函数

介绍

mutmutable的缩写,意思是 可变的

struct 类型是值类型,其实例成员函数无法修改实例本身。例如,下例中,成员函数 g 中不能修改成员变量 i 的值。

javascript
struct Foo {
    var i = 0

    public func g() {
        i += 1 // 错误  instance member variable 'i' cannot be modified in immutable  functionCangjie
    }

    public func f() {
        this.i += 1 // 错误  instance member variable 'i' cannot be modified in immutable functionCangjie
    }
}

mut 函数是一种可以修改 struct 实例本身的特殊的实例成员函数。在 mut 函数内部,this 的语义是特殊的,这种 this 拥有原地修改字段的能力。

注意:

只允许在 interface、struct 和 struct 的扩展内定义 mut 函数(class 是引用类型,实例成员函数不需要加 mut 也可以修改实例成员变量,所以禁止在 class 中定义 mut 函数)。

mut 函数定义

  1. mut 函数与普通的实例成员函数相比,多一个 mut 关键字来修饰。
javascript
struct Foo {
    var i = 0

    public mut func g() {
        i += 1  // Ok
    }
}
  1. mut 只能修饰实例成员函数,不能修饰静态成员函数。
javascript
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'
}
  1. mut 函数中的 this 不能被捕获,也不能作为表达式。不能在 mut 函数中对 struct 的实例成员变量进行捕获。

    javascript
    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 函数

  1. 接口中的实例成员函数,也可以使用 mut 修饰
javascript
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
}
  1. struct 的实例赋值给 interface 类型时是拷贝语义,因此 interfacemut 函数并不能修改 struct 实例的值。
javascript
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
}

mut 函数的使用限制

  1. 因为 struct 是值类型,所以如果一个变量是 struct 类型且使用 let 声明,那么不能通过这个变量访问该类型的 mut 函数。

    javascript
    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
    }
  2. 为避免逃逸,如果一个变量的类型是 struct 类型,那么这个变量不能将该类型使用 mut 修饰的函数作为一等公民来使用,只能调用这些 mut 函数。

    javascript
    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
    }
  3. 为避免逃逸,非 mut 的实例成员函数(包括 lambda 表达式)不能直接访问所在类型的 mut 函数,反之可以。

    javascript
    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
        }
    }

Released under the MIT License.