DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: l_hx
今日帖子: 4
在线用户: 3
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/18 15:08:30
标题:
求助tarry<string>,array of string,tstringlist,tlist<string>四者如何互相转换 浏览:682
加入我的收藏
楼主: var 
a:tarry<string>;
b:array of string;
c:tstringlist;
d:tlist<string>;
四者如何互相转换,最好用现成的方法或函数,谢谢.
----------------------------------------------
-
作者:
男 supermay (supermay) ★☆☆☆☆ -
盒子活跃会员
2023/2/18 15:30:27
1楼: TStringList.ToStringArray
TArray<string>与array of string是等价的,可以用copy
----------------------------------------------
链接:https://pan.baidu.com/s/12jzmECYKhGCsHBxz8tmB6w 提取码:pelr --来自百度网盘超级会员V9的分享
作者:
男 roadrunner (roadrunner) ★☆☆☆☆ -
盒子活跃会员
2023/2/18 15:54:21
2楼: tarray<string>和array of string完全一样,两个类型的变量可以直接互相赋值也可以直接写在参数里
tstringlist与tarray<string>的相互转换
c := tstringlist.create; c.addstrings(a); //copy a to c
a := c.tostringarray; //copy c to a

tlist<string>与Tarray<string>的相互转换
d := TList<string>.Create(a); //copy a to d
a := d.ToArray; //copy d to a

tlist<string>与TStringList的相互转换
d := TList<string>.Create(c); //copy c to d
c := TStringList.Create; c.AddStrings(d.ToArray); //copy d to c
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/18 18:10:24
3楼: @supermay 谢谢,可否写一下copy的代码,我写出来报错呀,是在FMX里哦.
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/18 18:12:54
4楼: @roadrunner 谢谢
tarray<string>和array of string完全一样,两个类型的变量可以直接互相赋值也可以直接写在参数里-----可否写一下,我的始终报错,是在FMX里哦.
----------------------------------------------
-
作者:
男 z_y_b_delphi (z_y_b_delphi) ★☆☆☆☆ -
普通会员
2023/2/18 21:34:41
5楼: tarray<string>和array of string用法一样,但不能copy,也不能直接互相赋值,参数也不能相互替代。
var
  TS:TArray<string>;
  Arr:array of string;
begin
 for var i := 0 to 99 do
      TS:=TS+[i.ToString];
  SetLength(Arr,100);
  Move(TS[0],Arr[0],Length(TS)*4);
  for var i := 0 to 99 do
    Memo1.Lines.Add(Arr[i]);
end;
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/2/18 21:42:51
5楼: tarray<string>和array of string的数据内存结构是一样的, 但是类型不一样
能否互相直接赋值要看delphi版本
我记得好像是从11开始支持直接赋值的 10的版本不行(也许是XE系列不行 10开始可以的 忘了)

还有另外一个类型TStringDynArray 和tarray<string>才是同一个类型
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/18 22:17:34
6楼: @z_y_b_delphi 谢谢 可是可以就是麻烦了点
@hs_kill 谢谢 我是11.2,直接a:=b或b:=a都报错呢
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/2/19 0:11:00
7楼: 刚试了一下, 确实不能直接赋值, 感觉像是编译器没有做完整

对于函数参数来说
var
  a: TArray<string>;
  b: array of string;

如果定义成array of string 是可以同时接受array of string和TArray<string>类型传入的:
procedure xx1(const s: array of string);

xx1(a) //正常
xx1(b) //正常

如果定义成TArray<string> 只能接受TArray<string>类型传入
procedure xx2(const s: TArray<string>);

xx2(a) //正常
xx2(b) //错误

但是对于变量 这2个类型无法互相赋值(直接move不算)
a := b //错误
b := a //错误

特别的是: 如果定义了2个变量 分别是array of string 也不能互相赋值
var
  b: array of string;
  c: array of string;

b := c //错误
c := b //错误

但是定义2个TArray<string> 是可以互相赋值的
var
  a1: TArray<string>;
  a2: TArray<string>;

a1 := a2 //正确

原因不明, 估计是编译器的处理问题吧
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 z_y_b_delphi (z_y_b_delphi) ★☆☆☆☆ -
普通会员
2023/2/19 7:52:31
8楼: Move在知道String数组长度的时候可用,string数组是不定长的,因此用起来也不方便。
用泛型copy是比较好的解决方案:
uses System.Generics.Collections;
var
  TS:TArray<string>;
  Arr:array of string;
begin
  for var i := 0 to 99 do
      TS:=TS+[i.ToString];
  SetLength(Arr,100);
  TArray.Copy<String>(TS,Arr,100);
end;
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/20 13:41:06
9楼: @hs_kill 谢谢 我是11.2试了一下 
函数形参是array of string的时候传入array of string或者tarray<string>都可以 
函数形参是tarray<string>的时候传入array of string不行 
如果定义了2个变量 分别是array of string 如果都在函数内部定义是可以互相赋值的 如果一个是形参一个是实参就会提示'不兼容的类型,Dynmic array和array of string'

@z_y_b_delphi 谢谢 TS:=TS+[i.ToString]; 没想到还有这种添加元素的用法,神奇,TS这里是当指针用吗,岂不是list<string>都可以不用了.
----------------------------------------------
-
作者:
男 z_y_b_delphi (z_y_b_delphi) ★☆☆☆☆ -
普通会员
2023/2/20 14:31:27
10楼: 提醒一下,动态数组赋值是引用!
比如:
  Arr1,Arr2:TArray<string>;
  Arr1:=Arr2;
那么Arr1的元素发生改变,Arr2也随之一起变化,就像这样:
  Arr1[0]:='Test';
  Arr2[0]也随之变为'Test'。
如果想让Arr1与Arr2不相关联,只能用TArray.Copy。
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/20 23:48:21
11楼: @z_y_b_delphi 这个确实 Copy相当于c#里面的clone
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/2/21 9:33:46
12楼: TS:=TS+[i.ToString] 这种写法尽量不要在循环内使用, 因为每一次+都是重新分配内存+copy
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/22 13:00:10
13楼: @hs_kill  如果用Tlist<String>的Add不也要重新分配内存和复制吗 效率不一样么
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/2/22 16:52:19
14楼: Delphi 里面的 string 对它的引用是引用的指针。比如:

A := 'abcd';  这里的 A 是指针;

B := A;  这里仅仅是把 A 的指针给了 B,原来的那个字符串只是多了一个引用。没有另外分配空间,复制字符串。

但是,如果是:

A := 'abcd';
B := A;
A := '1234';  《--- 到这里,因为 A 的内容被改了,但 B 仍然是以前的内容 abcd,因此,这里新分配了空间。分配空间比较消耗 CPU。


关于分配空间比较消耗 CPU 这个事情,不管是 Delphi 还是 C,都有一个技巧,就是预先分配一个比较大的空间。比如以下代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  List.Capacity := 100; //如果没有这行代码,那么,每次 add 可能都要重新分配空间。这行代码就预先分配足够空间。
  List := TStringList.Create;
  for i := 0 to 99 do
  begin
    List.Add(i.ToString);
  end;
end;


再说 TArray<string>,看看 Delphi 自己的代码:
function TStrings.ToStringArray: TArray<string>;
var
  I: Integer;
begin
  SetLength(Result, Count);
  for I := 0 to Count - 1 do
    Result[I] := Strings[I];
end;

上面那个代码,第一行,SetLength 就是预先分配空间。当然,这里分配的空间其实不是字符串的空间,而是字符串指针。

接下来的 Result[i] := Strings[i] 其实就是把里面的每一条字符串的指针复制过去。因为没有复制字符串,而是仅仅复制指针,效率还是很高的。
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/2/23 9:10:15
15楼: 拼接字符串, 重新分配内存和复制是无法避免
但是尽量减少次数
如果再循环内部用 A := A + B这种写法 相当于每次循环都要重新分配内存+复制, 因为这样写是增加数组长度, 成增加数组长度会触发重新申请内存

如果是list<string>, 相当于每次add都是添加了一个指针引用(string本质是个指针)
最后输出的时候再根据长度一次性申请内存做复制

所以简单点的理解,使用list循环添加只会触发一次内存分配, 而A := A+B会触发N次

  for var i := 0 to 99 do
      TS:=TS+[i.ToString];
  SetLength(Arr,100);

对于这段代码, 如果不想用list, 可以这样写
  setlength(TS, 100)
  for var i := 0 to 99 do
      TS[i]:= i.ToString;
这样只有最开始分配了一次内存, 后面都是指针引用
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/2/23 15:50:15
16楼: @pcplayer 如果设置List.Capacity := 90;添加100个还是可以添加进去呢.超额的10个又会重新分配是吗
@hs_kill 好的
----------------------------------------------
-
作者:
男 wuxiangyang (wxy) ★☆☆☆☆ -
盒子活跃会员
2023/2/23 16:04:16
17楼:
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/2/23 22:49:09
18楼: 16楼:是的,超过 100 个又会重新分配。

这里的策略是:
1. 一次分配一个大的内存空间,但也不要太大免得用不着还要占用内存。够大但不太大,这个得看你自己的程序具体面临的情况而定。假设 100 是一个合理的数字,那么,

2. 至少避免了在循环中,连续100次分配内存空间,而是只分配一次。

3. 如果超过 100,那你再次重新分配,给它 200,而不是 101,这样,就把 200 次 add 需要分配 200 次内存的操作,变成了只分配 2 次。

假设你知道你的具体应用环境是 1000 才够用,那你就不要分配 100,而是直接分配 1000 了。这样的策略,是多数软件都会采用的。这样会降低 CPU 消耗。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行51.75781毫秒 RSS