Delphi中最基本的列表是TList类和TList<T>泛型类,还有线程安全的TThreadList类和TThreadList<T>泛型类,底层实现是数组。Go用的是container/list包,内部实现是双向链表。

Delphi

TList

TList里存的是指针,使用时注意处理好指针即可。

//声明
var l: TList;
//构造
l := TList.Create;
//添加
l.Add(p);
//元素个数
n := l.Count;
//列表容量
cap := l.Capacity;
//取值
p1 := l.Items[0];
p2 := l.Extract(p1); //找到指针p1并从列表中取出,列表中将不再有p1,若其后还有元素,则前移填充空缺。
p := l.First;        //取第一个元素
p := l.Last;         //取最后一个元素
//查找元素的索引
i := l.IndexOf(p);
//修改
l.Items[0] := p2;
//删除
l.Delete(0);
l.Remove(p2);
//清空
l.Clear;             //只清空了内部的指针数组,并没有释放指针指向的内存
//释放
l.Free;

引用System.Contnrs单元后可以使用TObjectList类和TComponentList类,操作方法与TList相同,只是删除元素或清空列表后可自动释放元素。

TThreadList

TThreadList是加了锁的TList,所以多线程操作时是线程安全的。

//声明
var tl: TThreadList;
//构造
tl := TThreadList.Create;
//添加
tl.Add(p);
//删除
tl.Remove(p);
//加锁
l := tl.LockList; //返回TList,方便更精细的操作
//解锁
tl.UnlockList;
//清空
tl.Clear;         //同TList,只清空了内部的指针数组,并没有释放指针指向的内存
//释放
tl.Free;

TList<T>

需要引用System.Generics.Collections单元,使用方法与TList类似。

//操作元素以记录为例
TR = record
  i: Integer;
  s: string;
end;
//声明
var rl: TList<TR>;
//构造
rl := TList<TR>.Create;
//添加
rl.Add(R1);           //返回添加的位置
rl.Insert(1, R2);     //在指定位置插入
//删除
rl.Remove(R1);        //按元素删除
rl.Delete(0);         //按索引删除一个元素
rl.DeleteRange(0, n); //按索引删除连续多个元素
R := rl.Extract(R2);  //提取元素
R := rl.ExtractAt(0); //按索引提取元素
//清空
rl.Clear;             //会自动释放元素所占内存
//释放
rl.Free;

TThreadList<T>

TThreadList<T>是加了锁的TList<T>,多线程操作时是线程安全的。

//声明
var rtl: TThreadList<TR>;
//构造
rtl := TThreadList<TR>.Create;
//添加
rtl.Add(R);
//删除
rtl.Remove(R);
//加锁
rl := rtl.LockList; //返回TList<TR>,方便更精细的操作
//解锁
rtl.UnlockList;
//清空
rtl.Clear;
//释放
rtl.Free;

Go

//声明
var l list.List                //l是List结构体
l := list.New()                //l是指向List结构体的指针
//添加
e1 := l.PushFront(123)         //在头部添加元素
e2 := l.PushBack("abc")        //在尾部添加元素
e3 := l.InsertAfter("xyz", e1) //在指定元素后添加新元素
e4 := l.InsertBefore(456, e2)  //在指定元素前添加新元素
//取值
e5 := l.Front()                //返回第一个元素
e6 := l.Back()                 //返回最后一个元素
//从头顺序遍历
for i := e5; i != nil; i = i.Next() {
  fmt.Println(i.Value)
}
//从尾逆序遍历
for i := e6; i != nil; i = i.Prev() {
  fmt.Println(i.Value)
}
//移动元素
l.MoveToFront(e3)              //把e3移动到头部
l.MoveToBack(e4)               //把e4移动到尾部
l.MoveAfter(e1, e3)            //把e1移动到e3后面
l.MoveBefore(e2, e1)           //把e2移动到e1前面
//删除
l.Remove(e3)
//元素个数
n := l.Len()
//清空
l.Init()

由于Go语言语法糖的原因,指针与指针指向的对象的使用方法完全一致。

10-31 05:58