所有权系统 #

一、所有权概念 #

1.1 什么是所有权 #

Mojo的所有权系统是一种内存管理机制,确保:

  • 每个值都有一个所有者
  • 值在同一时间只能有一个所有者
  • 所有者离开作用域时,值被释放

1.2 所有权规则 #

  1. 每个值都有一个变量作为其所有者
  2. 同一时间只能有一个所有者
  3. 当所有者离开作用域,值将被丢弃
mojo
struct Resource:
    var name: String
    
    fn __init__(inout self, name: String):
        self.name = name
        print(f"{self.name} created")
    
    fn __del__(owned self):
        print(f"{self.name} destroyed")

def main():
    let res = Resource("MyResource")
    print("Using resource")

main()

二、所有权转移 #

2.1 转移语义 #

mojo
struct Buffer:
    var data: Pointer[Int]
    var size: Int
    
    fn __init__(inout self, size: Int):
        self.size = size
        self.data = Pointer[Int].alloc(size)
    
    fn __del__(owned self):
        self.data.free()

fn take_buffer(owned b: Buffer):
    print(f"Buffer size: {b.size}")

def main():
    let buf = Buffer(10)
    take_buffer(buf)

main()

2.2 转移后不可用 #

mojo
struct Item:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

fn consume(owned item: Item):
    print(item.value)

def main():
    let item = Item(42)
    consume(item)
    print(item.value)

main()

2.3 返回值所有权 #

mojo
struct Item:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

fn create_item() -> Item:
    return Item(100)

def main():
    let item = create_item()
    print(item.value)

main()

三、借用 #

3.1 不可变借用 (ref) #

mojo
struct Data:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

fn read_data(ref d: Data):
    print(d.value)

def main():
    let data = Data(42)
    read_data(data)
    print(data.value)

main()

3.2 可变借用 (inout) #

mojo
struct Counter:
    var value: Int
    
    fn __init__(inout self, value: Int = 0):
        self.value = value

fn increment(inout c: Counter):
    c.value += 1

def main():
    var counter = Counter()
    increment(counter)
    print(counter.value)

main()

3.3 借用规则 #

  • 可以有多个不可变借用
  • 只能有一个可变借用
  • 不可变借用和可变借用不能同时存在
mojo
struct Data:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

fn read1(ref d: Data):
    print(d.value)

fn read2(ref d: Data):
    print(d.value)

fn modify(inout d: Data):
    d.value += 1

def main():
    var data = Data(10)
    
    read1(data)
    read2(data)
    
    modify(data)
    
    print(data.value)

main()

四、引用类型 #

4.1 ref参数 #

mojo
struct Point:
    var x: Int
    var y: Int
    
    fn __init__(inout self, x: Int, y: Int):
        self.x = x
        self.y = y

fn distance(ref p1: Point, ref p2: Point) -> Float64:
    let dx = p2.x - p1.x
    let dy = p2.y - p1.y
    return (dx * dx + dy * dy) ** 0.5

def main():
    let p1 = Point(0, 0)
    let p2 = Point(3, 4)
    print(distance(p1, p2))

main()

4.2 inout参数 #

mojo
struct Point:
    var x: Int
    var y: Int
    
    fn __init__(inout self, x: Int, y: Int):
        self.x = x
        self.y = y

fn translate(inout p: Point, dx: Int, dy: Int):
    p.x += dx
    p.y += dy

def main():
    var point = Point(10, 20)
    translate(point, 5, 5)
    print(f"({point.x}, {point.y})")

main()

4.3 owned参数 #

mojo
struct Resource:
    var name: String
    
    fn __init__(inout self, name: String):
        self.name = name
        print(f"{self.name} acquired")
    
    fn __del__(owned self):
        print(f"{self.name} released")

fn use_resource(owned r: Resource):
    print(f"Using {r.name}")

def main():
    let res = Resource("Database")
    use_resource(res)
    print("Done")

main()

五、生命周期 #

5.1 生命周期注解 #

mojo
struct StringRef:
    ref var data: String
    
    fn __init__(inout self, ref s: String):
        self.data = s
    
    fn get(self) -> ref String:
        return self.data

def main():
    let text = "Hello"
    var sref = StringRef(text)
    print(sref.get())

main()

5.2 生命周期约束 #

mojo
struct Container:
    ref var item: Item
    
    fn __init__(inout self, ref i: Item):
        self.item = i

struct Item:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

def main():
    let item = Item(42)
    let container = Container(item)
    print(container.item.value)

main()

六、复制与移动 #

6.1 复制语义 #

mojo
struct SimpleValue:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value
    
    fn __copyinit__(inout self, other: SimpleValue):
        self.value = other.value

def main():
    let v1 = SimpleValue(10)
    let v2 = v1
    
    print(v1.value)
    print(v2.value)

main()

6.2 移动语义 #

mojo
struct UniqueResource:
    var id: Int
    
    fn __init__(inout self, id: Int):
        self.id = id
    
    fn __moveinit__(inout self, owned other: UniqueResource):
        self.id = other.id
        other.id = 0

def main():
    var r1 = UniqueResource(100)
    var r2 = r1
    
    print(r2.id)

main()

6.3 禁止复制 #

mojo
struct NonCopyable:
    var data: Pointer[Int]
    
    fn __init__(inout self, size: Int):
        self.data = Pointer[Int].alloc(size)
    
    fn __del__(owned self):
        self.data.free()

def main():
    let nc = NonCopyable(10)

main()

七、所有权最佳实践 #

7.1 优先使用借用 #

mojo
struct Data:
    var values: List[Int]
    
    fn __init__(inout self):
        self.values = [1, 2, 3, 4, 5]

fn process(ref d: Data):
    for v in d.values:
        print(v)

def main():
    let data = Data()
    process(data)
    process(data)

main()

7.2 明确所有权转移 #

mojo
struct Buffer:
    var data: Pointer[Int]
    var size: Int
    
    fn __init__(inout self, size: Int):
        self.size = size
        self.data = Pointer[Int].alloc(size)
    
    fn __del__(owned self):
        if self.data != nullptr:
            self.data.free()

fn transfer_buffer(owned b: Buffer) -> Buffer:
    return b

def main():
    let buf1 = Buffer(10)
    let buf2 = transfer_buffer(buf1)

main()

7.3 使用RAII #

mojo
struct FileHandle:
    var path: String
    var handle: Int
    
    fn __init__(inout self, path: String):
        self.path = path
        self.handle = open_file(path)
        print(f"Opened {self.path}")
    
    fn __del__(owned self):
        close_file(self.handle)
        print(f"Closed {self.path}")

fn open_file(path: String) -> Int:
    return 1

fn close_file(handle: Int):
    pass

def main():
    let file = FileHandle("data.txt")
    print("Processing file")

main()

八、常见问题 #

8.1 悬垂引用 #

mojo
fn create_ref() -> ref Int:
    let local = 10
    return local

def main():
    let r = create_ref()

main()

8.2 双重释放 #

mojo
struct Resource:
    var ptr: Pointer[Int]
    
    fn __init__(inout self):
        self.ptr = Pointer[Int].alloc(10)
    
    fn __del__(owned self):
        self.ptr.free()

def main():
    let r1 = Resource()
    let r2 = r1

main()

8.3 数据竞争 #

mojo
struct SharedData:
    var value: Int
    
    fn __init__(inout self, value: Int):
        self.value = value

fn read_write(ref d: SharedData):
    print(d.value)
    d.value += 1

def main():
    var data = SharedData(10)
    read_write(data)

main()

九、总结 #

本章学习了:

  • 所有权概念与规则
  • 所有权转移
  • 借用机制
  • 引用类型
  • 生命周期
  • 复制与移动语义
  • 最佳实践

下一章,我们将学习指针与引用。

最后更新:2026-03-27