zoukankan      html  css  js  c++  java
  • 当泛型遇上结构体...

    一般使用泛型都是放类啊, 基础类型什么的, 所以使用上和非泛型基本没什么区别, 不过昨天有人在群里问的问题到是暴露了一个特例:

      TRC = record
        Str: string;
        Int: Integer;
      end;
    
    ...
    
    var
      nRC: TRC;
      nList: TList<TRC>;
      i: Integer;
    begin
      nList := TList<TRC>.Create;
      for i := 0 to 9 do
      begin
        with nRC do
        begin
          Str := IntToStr(i);
          Int := i;
        end;
        nList.Add(nRC);
      end;
    
      nList[3].Str := 'ABC'; {这里会提示左边不允许赋值}
    
      nList.Free;
    end;

    显然, 如果不是一个结构体而是一个类型就没问题了, 先不说原因, 这里我先列出思路:

    首先编译器不允许赋值, 那么如果是属性呢?

      TRC = record
      private
        FStr: string;
      public
        Int: Integer;
        property Str: string read FStr write FStr;
      end;

    改成这样...可惜仍然不行, 继续

      TRC = record
      private
        FStr: string;
        function GetStr: string;
        procedure SetStr(const Value: string);
      public
        Int: Integer;
        property Str: string read GetStr write SetStr;
      end;
    
    ...
    
    function TRC.GetStr: string;
    begin
      Result := FStr;
    end;
    
    procedure TRC.SetStr(const Value: string);
    begin
      FStr := Value;
    end;
    
    ...
    
    var
      nRC: TRC;
      nList: TList<TRC>;
      i: Integer;
    begin
      nList := TList<TRC>.Create;
      for i := 0 to 9 do
      begin
        with nRC do
        begin
          Str := IntToStr(i);
          Int := i;
        end;
        nList.Add(nRC);
      end;
    
      ShowMessage(nList[3].Str);
      nList[3].Str := 'ABC';
      ShowMessage(nList[3].Str);
      nList.Free;
    end;

    这样, 编译器终于不报错了, 可惜赋值完全无效...2次的Showmessage都是3

    OK, 现在开始分析一下具体是怎么执行的

    Unit1.pas.54: nList[3].Str := 'ABC';
    004B4C74 8D4DE8           lea ecx,[ebp-$18]
    004B4C77 BA03000000       mov edx,$00000003
    004B4C7C 8BC6             mov eax,esi
    004B4C7E E83D0F0000       call Generics + $4B5BC0
    004B4C83 8D45E8           lea eax,[ebp-$18]
    004B4C86 BA204D4B00       mov edx,$004b4d20
    004B4C8B E8B0000000       call Generics + $4B4D40

    显然, 一开始先吧list里的内容复制出来一份临时数据, 然后给这个临时数据赋值, 然后...就没有然后了

    只是改变的临时数据, list里的内容完全没变化啊

    于是, 瞬间联想到, 如果一个类实例里的某一属性是结构体的话, 那么对其赋值和取值, 也是基于创建一个临时变量,修改其内容再全部替换的过程

    这样就好解释多了, 看来是不能直接修改结构体的单独一项, 那咱们换个方法

      TRC = record
        Str: string;
        Int: Integer;
      end;
    
    ...
    
    var
      nRC: TRC;
      nList: TList<TRC>;
      i: Integer;
    begin
      nList := TList<TRC>.Create;
      for i := 0 to 9 do
      begin
        with nRC do
        begin
          Str := IntToStr(i);
          Int := i;
        end;
        nList.Add(nRC);
      end;
    
      ShowMessage(nList[3].Str);
      nRC := nList[3];
      nRC.Str := 'ABC';
      nList[3] := nRC;
      ShowMessage(nList[3].Str);
      nList.Free;
    end;

    这样果然没问题了

    至于结构体为啥不能再类实例里直接修改其内部元素的问题, 这个有待继续研究...

  • 相关阅读:
    codechef Dynamic GCD [树链剖分 gcd]
    bzoj 4546: codechef XRQRS [可持久化Trie]
    bzoj 4835: 遗忘之树 [树形DP]
    bzoj 4033: [HAOI2015]树上染色 [树形DP]
    bzoj 4591: [Shoi2015]超能粒子炮·改 [lucas定理]
    3167: [Heoi2013]Sao [树形DP]
    bzoj 3812: 主旋律 [容斥原理 状压DP]
    有标号的二分图计数 [生成函数 多项式]
    有标号DAG计数 [容斥原理 子集反演 组合数学 fft]
    BZOJ 3028: 食物 [生成函数 隔板法 | 广义二项式定理]
  • 原文地址:https://www.cnblogs.com/lzl_17948876/p/3579698.html
Copyright © 2011-2022 走看看