AI Library · 知识库

# 复制与共享:浅复制与引用隔离

学习目标:通过嵌套配置修改,理解引用别名(Alias)、浅复制(Shallow Copy)与深复制(Deep Copy)的内存行为与隔离边界。

前置知识与范围:结构体/对象与引用。聚焦修改副本时,原对象字段是否产生意料之外的联动变化。

# 问题与边界

定义具有一层嵌套结构的配置:

# 关键差异

语言 默认赋值行为 浅复制机制 深复制机制
Rust 默认移动语义(Move);派生 Clone 结构体直接派生 Clone(值语义直接全深拷贝) clone() 默认递归拷贝
Go 结构体变量赋值为全量值拷贝 顶层值复制;若嵌套指针则为浅拷贝 递归构造新嵌套结构体
Java 变量赋值仅传递对象引用 clone() 或手动复制外层构造 递归 new 或序列化深拷贝
JavaScript 对象赋值为引用传递 展开运算符 { ...orig } 或 Object.assign 原生 structuredClone(orig)
TypeScript 沿用 JS 机制 展开运算符 structuredClone
Kotlin 引用传递 data class copy() 方法(浅拷贝) 递归构造独立子对象
Python 赋值为名称绑定引用 标准库 copy.copy(obj) 标准库 copy.deepcopy(obj)
C++ 默认全量值语义深拷贝 嵌套指针时需注意悬挂 拷贝构造函数默认深拷贝成员

# 各语言实现

# Rust

Rust#[derive(Clone, Debug, PartialEq)]
struct Server {
    host: String,
    port: u16,
}

#[derive(Clone, Debug, PartialEq)]
struct Config {
    env: String,
    server: Server,
}

fn main() {
    let original = Config {
        env: "prod".to_string(),
        server: Server { host: "127.0.0.1".to_string(), port: 8080 },
    };

    // Rust 的派生 Clone 默认对内部所有持有字段进行深度拷贝
    let mut cloned = original.clone();
    cloned.env = "stage".to_string();
    cloned.server.port = 9999;

    // 原对象完全不受影响
    assert_eq!(original.env, "prod");
    assert_eq!(original.server.port, 8080);
    assert_eq!(cloned.server.port, 9999);

    println!("orig_port: {}, cloned_port: {}", original.server.port, cloned.server.port);
}

Rust 的所有权模型杜绝了隐式别名共享导致的静默数据竞争;Clone 显式复制数据。

# Go

Gopackage main

import "fmt"

type Server struct {
	Host string
	Port int
}

type Config struct {
	Env    string
	Server *Server // 嵌套指针模拟浅拷贝场景
}

func main() {
	original := Config{
		Env:    "prod",
		Server: &Server{Host: "127.0.0.1", Port: 8080},
	}

	// 浅拷贝:顶层结构体值复制,但内部指针指向同一地址
	shallow := original
	shallow.Env = "stage"
	shallow.Server.Port = 9000

	if original.Env != "prod" {
		panic("top level should be isolated")
	}
	if original.Server.Port != 9000 {
		panic("nested pointer was shared and modified")
	}

	// 深拷贝:递归显式分配全新子指针
	deep := Config{
		Env: original.Env,
		Server: &Server{
			Host: original.Server.Host,
			Port: 8080, // 重置并独立
		},
	}
	deep.Server.Port = 9999

	if original.Server.Port != 9000 || deep.Server.Port != 9999 {
		panic("deep copy failed")
	}

	fmt.Printf("orig_port: %d, deep_port: %d\n", original.Server.Port, deep.Server.Port)
}

Go 结构体如果是纯值类型嵌套,赋值直接全量值复制;一旦包含指针切片字段,赋值即退化为浅拷贝。

# Java

Javapublic class Main {
    public static class Server {
        public String host;
        public int port;
        public Server(String host, int port) { this.host = host; this.port = port; }
    }

    public static class Config {
        public String env;
        public Server server;
        public Config(String env, Server server) { this.env = env; this.server = server; }
    }

    public static void main(String[] args) {
        Config original = new Config("prod", new Server("127.0.0.1", 8080));

        // 浅拷贝:复制外层,共享内层引用
        Config shallow = new Config("stage", original.server);
        shallow.server.port = 9000;

        assert "prod".equals(original.env);
        assert original.server.port == 9000 : "nested instance modified";

        // 深拷贝:递归分配独立子对象
        Config deep = new Config(original.env, new Server(original.server.host, 9999));
        assert original.server.port == 9000;
        assert deep.server.port == 9999;

        System.out.println("orig_port: " + original.server.port + ", deep_port: " + deep.server.port);
    }
}

Java 对象赋值只是复制堆指针;必须递归构造新对象才能切断引用连带修改。

# JavaScript

JavaScriptconst assert = {
  equal: (a, b) => { if (a !== b) throw new Error(`${a} !== ${b}`); },
  deepEqual: (a, b) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${JSON.stringify(a)} !== ${JSON.stringify(b)}`); },
  throws: (fn, errType) => {
    try { fn(); throw new Error("expected throw"); } catch (e) {
      if (e.message === "expected throw") throw e;
      if (errType && !(e instanceof errType)) throw e;
    }
  }
};

const original = {
  env: "prod",
  server: { host: "127.0.0.1", port: 8080 },
};

// 浅拷贝
const shallow = { ...original };
shallow.env = "stage";
shallow.server.port = 9000;

assert.equal(original.env, "prod");
assert.equal(original.server.port, 9000); // 内层连带被改

// 深拷贝(Node 17+ 原生支持 structuredClone)
const deep = structuredClone(original);
deep.server.port = 9999;

assert.equal(original.server.port, 9000);
assert.equal(deep.server.port, 9999);

console.log(`orig_port: ${original.server.port}, deep_port: ${deep.server.port}`);

标准库 structuredClone 成为现代 JS 进行深度结构拷贝的标准规范。

# TypeScript

TypeScriptconst assert = {
  equal: (a: unknown, b: unknown) => { if (a !== b) throw new Error(`${a} !== ${b}`); },
  deepEqual: (a: unknown, b: unknown) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${JSON.stringify(a)} !== ${JSON.stringify(b)}`); },
  throws: (fn: () => void, errType?: unknown) => {
    try { fn(); throw new Error("expected throw"); } catch (e: unknown) {
      if (e instanceof Error && e.message === "expected throw") throw e;
      if (typeof errType === "function" && !(e instanceof errType)) throw e;
    }
  }
};

interface Server {
  host: string;
  port: number;
}

interface Config {
  env: string;
  server: Server;
}

const original: Config = {
  env: "prod",
  server: { host: "127.0.0.1", port: 8080 },
};

const shallow: Config = { ...original };
shallow.env = "stage";
shallow.server.port = 9000;

assert.equal(original.env, "prod");
assert.equal(original.server.port, 9000);

const deep: Config = structuredClone(original);
deep.server.port = 9999;

assert.equal(original.server.port, 9000);
assert.equal(deep.server.port, 9999);

console.log(`orig_port: ${original.server.port}, deep_port: ${deep.server.port}`);

TypeScript 在编译时不会阻止对浅拷贝子对象的修改,除非显式使用 Readonly<T> 标记深度只读。

# Kotlin

Kotlindata class Server(var host: String, var port: Int)
data class Config(var env: String, var server: Server)

fun main() {
    val original = Config("prod", Server("127.0.0.1", 8080))

    // data class 的 copy() 是浅拷贝
    val shallow = original.copy(env = "stage")
    shallow.server.port = 9000

    check(original.env == "prod")
    check(original.server.port == 9000)

    // 深拷贝
    val deep = original.copy(server = original.server.copy(port = 9999))
    check(original.server.port == 9000)
    check(deep.server.port == 9999)

    println("orig_port: ${original.server.port}, deep_port: ${deep.server.port}")
}

Kotlin 的 data class.copy() 仅复制第一层属性,嵌套的可变对象必须逐层级显式 copy()。

# Python

Pythonimport copy

class Server:
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port

class Config:
    def __init__(self, env: str, server: Server):
        self.env = env
        self.server = server

if __name__ == "__main__":
    original = Config("prod", Server("127.0.0.1", 8080))

    # 浅拷贝
    shallow = copy.copy(original)
    shallow.env = "stage"
    shallow.server.port = 9000

    assert original.env == "prod"
    assert original.server.port == 9000

    # 深拷贝
    deep = copy.deepcopy(original)
    deep.server.port = 9999

    assert original.server.port == 9000
    assert deep.server.port == 9999

    print(f"orig_port: {original.server.port}, deep_port: {deep.server.port}")

Python 标准库模块 copy 严格区分并提供 copy.copy(浅拷贝)与 copy.deepcopy(深拷贝)。

# C++

C++#include <iostream>
#include <string>
#include <cassert>

struct Server {
    std::string host;
    int port;
};

struct Config {
    std::string env;
    Server server;
};

int main() {
    Config original{"prod", {"127.0.0.1", 8080}};

    // C++ 默认全值语义赋值就是深拷贝
    Config deep = original;
    deep.env = "stage";
    deep.server.port = 9999;

    assert(original.env == "prod");
    assert(original.server.port == 8080);
    assert(deep.server.port == 9999);

    std::cout << "orig_port: " << original.server.port << ", deep_port: " << deep.server.port << "\n";
}

C++ 的值语义体系在缺省情况下对由标准库值类型组成的结构体执行递归全量深复制。

# 迁移误区与适用限制

# 运行与验证

语言版本基线见示例基线。 所有程序运行后控制台输出均为:

纯文本orig_port: 9000, deep_port: 9999

浅拷贝连带修改与深拷贝完全隔离断言均已通过(Rust/C++ 针对值语义完全隔离验证)。

# 相关阅读