• d玩转不变


    领域驱动设计

    值对象视为不变的.使无副作用函数,不依赖可变状态.
    域事件一般不变,不应修改域代码操作的数据,相反,总是返回新数据.
    大量使用UFCS域链来限制使用内存.
    最好静态保证!

    想用不变,传统上:

    struct ArrayContainer
    {
        @ConstRead
        private int[] array_;
        ...
        mixin(GenerateFieldAccessors);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但,基于模板:构建慢,内存使用率高.脆弱,对编译器更改敏感,不可传递:需要array_的潜在副本

    想要:

    immutable struct ArrayContainer
    {
        int[] array;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    但不能用不变!
    ● 想使用不变数据类型.
    ● 想使用区间.
    ● 还使用了很多关联数组.
    ● 但是不变数据类型打破了许多区间,并且不适合关联数组!

    immutable struct S { int i; }
    ...
    auto list = [S(2), S(4), S(3)];
    
    • 1
    • 2
    • 3

    错误,不能修改....不能用不变.

    immutable struct S { int i; }
     ...
     auto list = [S(2), S(4), S(3)];
     assert(list.maxElement!"a.i"== S(4);
    //错误!无法修改.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    为何?如下,很明显应工作:

    T fun(T)(T arg1, T arg2) {
          T result = arg1;
          result = arg2;
          return result;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不能用Unqual!

    T fun(T)(T foo, T bar) { Unqual!T result = foo; result = bar; return result; }
    
    • 1

    Unqual,只是去掉最外层限定符.字段,仍然是不变的.

    immutable struct S { int i; }
      void main() {
          Unqual!S s;
           static assert(!is(typeof(s) == S));
           s = S(5);
      }
    //错误!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果覆盖不变,会怎样?

    immutable struct S {
        int field;
    }
    
    void genericFun(T)(T first, T second) {
        auto store = first;
        immutable int* ptr = &store.field;
        int firstField = *ptr;
        store = second; // 危险!
        int secondField = *ptr;
        // 失败!
        assert(firstField == secondField);
        // 观察到了不变指针改变它的值,全部丢失,等等
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    问题,是不能修改不变字段.观察不变引用,改变了不变.用头可变放松常系统?

    struct Turducken(T) {
        Turkey store;
        struct Turkey {
            Duck duck;
        }
        union Duck {
            Chicken chicken;
        }
        alias Chicken = T;//`T`封装在`联`中的`构`中
    //即使T有不变成员.
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    因为是,所以不调用析构器.
    因为是结构体,所以,即使T有不变商店,也可用std.algorithm.mutation.moveEmplace().
    可以控制生命期.故意的.
    缺点是,未来可能会改变.

    如何写头可变

    align(T.alignof)
    struct HeadMut(T) {
         void[T.sizeof] data;
    }
    
    • 1
    • 2
    • 3
    • 4

    精确扫描GC问题:始终按指针对待void[n].
    想要DeepUnqual.用DeepUnqual来帮助.
    rebindable.DeepUnqual,为每个D数据类型定义等效类型.可变指针在一堆.不变指针在另一堆.其他,都不一样.

    DeepUnqual!T精确GC,扫描扫描T的字段.相同大小,相同对齐(中性),同它工作,是深度不安全!你要转换一切.
    置(T)==>重绑定(T)(神秘)==>T 取().

    如何保存T,如何取T?

    Rebindable value;
    value.set(S(5));
    assert(value.get == S(5));
    //即使S为不变.
    
    • 1
    • 2
    • 3
    • 4

    但,安全吗?

    秘密吗?安全吗?
    ● 只要T是秘密的,它就是安全的.
    D不变混合了内存不变性可观察性.
    ● 只要未观察到变化.就不在乎值是否变化.
    Rebindable!T是包装T.
    ● 不能按T形式取包含数据引用,因为get按值返回.
    ● 由于DeepUnqual,存储的数据可变的,因此可以改变Rebindable!T.从不改变未声明可变内存.
    ● 并且内存自身未按不变公开,而是返回不变值副本.

    虽然数据存储在Rebindable中,但它是可变化的,但每次变化都必须是从有效状态到有效状态,无法在变化过程抓到它.
    ● 弱点:T不能依赖由构造函数或者复制构造函数创建的每个地址.
    ● 如果复制构造函数到处搞乱字段地址,就会中断.

    还有:Nullable, rebindable.Nullable工具.

    Nullable!(const int) ni;
    assert(ni.isNull);
    ni = 5;
    assert(!ni.isNull && ni.get == 5);
    ni.nullify;
    assert(ni.isNull);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    不变安全的关联数组,rebindable.AssocArray

    AssocArray!(int, S) assocArray;
    assocArray[0] = S([5]);
    assocArray[0] = S([6]);
    assert(assocArray[0] == S([6]));
    
    • 1
    • 2
    • 3
    • 4

    建议:可引用性万恶之源.
    immutable是不是太强大了?应该可覆盖不变字段吗?
    ● 否:不变太弱了!
    ● 问题是可观察不变字段的变化.
    ● 默认,可&i并取得i的永久视图:&iimmutable(int)*,但可能改变值!
    ● 什么比不变更强大?右值!

    右值:只能出现在右边的,就叫右值.

    假设右值结构{}可比不变结构更强大,但仍可通过分配新值来覆盖!
    右值构是纯数据结构:不取字段地址,不引用字段,不直接分配字段.

    为什么?这样,就不必害怕突变,因为没有人能抓住我们.
    ● 如果只赋值新构建T值,则不会破坏不变性.
    纯右值不变更强:它是不可引用的,因此是不可观察的.
    ● 事实上,它没有内存:它仅是数据,不保存在内存中.
    ● 可读取它的值,但不能远程观察它的字段,因为它是旧数据.

    实际可行建议:彻底删除不变结构字段.
    为什么Unqual!T不起作用?为什么Unqual!T不应工作?
    标准库假定Unqual!T头可变.
    结构内部可隐藏不变字段,创建独立不变补丁.

    immutable struct S
    {
      //实际上,仅能通过`不变本`访问immutable(int)[]
      int[] a;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Unqual已为构外类型创建头可变值.
    字段实际上总是头可变的,immutable(T)仅为T var设置默认值.

    实际上,不变使每个字段为Unqual!(immutable T).
    直接访问可变(T.field)字段,先隐式转为不变,如果不能,则是错误.
    这保留了,保留了不变,不需要访问器.

    但允许在数据结构中,通过Unqual!T使用任何T.效果:Unqual!T==HeadMutable!T,总是.但未完全解决类的头可变问题.(immutable(Object)不会隐式转换到Object.).但是在域代码中,不会使用类.:-)无论如何,存在std.typecons.Rebindable.

    代码位置

  • 相关阅读:
    可执行jar包和可依赖jar包同时生效
    离线地图开发-含源代码(免费)
    Android 性能优化—— 启动优化提升60%
    todo-list案例(一) 静态组件
    Python 自定义模块和包设计英语生词本(文件版)
    函数指针模板
    vue el-select搜索功能--区分输入内容后得到的是否是下拉框选择数据
    MES管理系统解决方案需要具备的7个特点
    宇视雷达&雷视交付|问题定位(素材收集篇)
    SD155非接触五维位移监测仪应用桥梁监测
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/126186676