You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Unity中的Vector3等结构体实现不可变性?

在C#中实现符合函数式理念的不可变Vector3结构体

核心原则

函数式编程中不可变类型的核心是:实例一旦创建,内部状态就永远无法修改。所有“修改”操作都通过返回新实例来完成,原实例保持完全不变。对于C#的结构体(值类型),我们可以通过以下方式实现这一点:

具体实现方案

1. 使用readonly struct + 只读字段/属性

C# 7.2及以上支持readonly struct,编译器会强制结构体内部所有字段都是只读的,且不允许任何修改字段的操作,从语法层面保证不可变性。

public readonly struct ImmutableVector3
{
    // 只读字段,初始化后无法修改
    public readonly float X;
    public readonly float Y;
    public readonly float Z;

    // 唯一的构造函数,必须初始化所有字段
    public ImmutableVector3(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    // 单字段更新方法:返回新实例,不修改原对象
    public ImmutableVector3 WithX(float newX) => new ImmutableVector3(newX, Y, Z);
    public ImmutableVector3 WithY(float newY) => new ImmutableVector3(X, newY, Z);
    public ImmutableVector3 WithZ(float newZ) => new ImmutableVector3(X, Y, newZ);

    // 向量运算方法:返回新的运算结果,原向量保持不变
    public ImmutableVector3 Add(ImmutableVector3 other)
    {
        return new ImmutableVector3(
            X + other.X,
            Y + other.Y,
            Z + other.Z
        );
    }

    public ImmutableVector3 Scale(float scalar)
    {
        return new ImmutableVector3(
            X * scalar,
            Y * scalar,
            Z * scalar
        );
    }

    // 重载运算符,让使用更符合C#习惯
    public static ImmutableVector3 operator +(ImmutableVector3 a, ImmutableVector3 b)
        => a.Add(b);

    public static ImmutableVector3 operator *(ImmutableVector3 vec, float scalar)
        => vec.Scale(scalar);

    // 可选:重写ToString方便调试
    public override string ToString()
        => $"({X:F2}, {Y:F2}, {Z:F2})";
}

2. 使用示例

所有操作都不会改变原实例,只会生成新的不可变向量:

// 创建初始向量
var baseVec = new ImmutableVector3(1.0f, 2.0f, 3.0f);

// 生成新向量,原baseVec完全不变
var shiftedVec = baseVec.WithY(5.0f);
var sumVec = baseVec + new ImmutableVector3(4.0f, 3.0f, 2.0f);
var scaledVec = baseVec * 2.0f;

// 输出:baseVec仍然是(1.00, 2.00, 3.00)
Console.WriteLine(baseVec);

针对Unity等场景的补充

如果是在Unity中使用(Unity自带的Vector3是可变结构体),你可以:

  • 封装自己的ImmutableVector3类型,如上所示
  • 在业务逻辑中严格使用不可变版本,仅在与Unity API交互时(比如设置Transform位置)临时转换为Unity原生Vector3

关于可变状态的边界处理

你提到的数据库这类不可避免的可变状态,函数式编程的思路是:

  • 将可变状态隔离在边界层(比如数据访问层)
  • 业务逻辑层完全使用不可变数据,所有操作都是纯函数(输入确定则输出确定,无副作用)
  • 状态的变更通过“获取旧状态→生成新状态→写入边界层”的流程完成,避免在核心逻辑中直接修改状态

内容的提问来源于stack exchange,提问作者John Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:05