前言

最开始学习数据结构的时候,链表,堆栈,队列,数组,似乎只是一堆概念,随着使用中慢慢接触,其对应的模型,功能,一个个跃到眼前,变成了复杂模型数据处理中的最重要的部分。---By Murphy 20180424

1,列表

Delphi中的列表有很多,从数据结构上可以分作:TList(数据链),TQueue(队列),TStack(堆栈),TDictionary(字典表)等等; 而从功能上又可以分作TList(列表),TObjectList(对象列表),TComponentList(组件列表),TStringList(字串列表),TClassList(类列表)。

列表的数据结构性,决定了列表的基础方法,基本都是以增删改查,计数,排序为主;而功能列表中,进一步增强了对每个节点元素的检查和限制,从而增加了针对这种数据类型的更贴合的功能,例如:对象的自动销毁,或仅结构移除,构建排序比较规则等等。现在就让我们看几种具有代表性的列表

a,TList

我们首先来看看TList在DelphiRX10中的源码定义

TList = class(TObject)
  private
    FList: TPointerList;     
    FCount: Integer;
    FCapacity: Integer;
  protected
    function Get(Index: Integer): Pointer;
    procedure Grow; virtual;
    procedure Put(Index: Integer; Item: Pointer);
    procedure Notify(Ptr: Pointer; Action: TListNotification); virtual;
    procedure SetCapacity(NewCapacity: Integer);
    procedure SetCount(NewCount: Integer);
  public
    type
      TDirection = System.Types.TDirection;

destructor Destroy; override;
    function Add(Item: Pointer): Integer;                                                                               //添加一个新元素
    procedure Clear; virtual;                                                                                                  //清空列表
    procedure Delete(Index: Integer);                                                                                    //删除对象元素并销毁
    class procedure Error(const Msg: string; Data: NativeInt); overload; virtual;
    class procedure Error(Msg: PResStringRec; Data: NativeInt); overload;
    procedure Exchange(Index1, Index2: Integer);                                                                //交换对象
    function Expand: TList;                                                                                                     //扩展当前对象容量
    function Extract(Item: Pointer): Pointer; inline;                                                                  //移除对象元素,而不是销毁,并且返回对象指针
    function ExtractItem(Item: Pointer; Direction: TDirection): Pointer;                                   //从当前对象指针开始定向定位,查找到对应对象并移除  
    function First: Pointer; inline;                                                                                             //当前对象指针移动到第一个元素
    function GetEnumerator: TListEnumerator;                                                                       //一个抽象列表,没看懂这里的扩展性设计
    function IndexOf(Item: Pointer): Integer;                                                                           //检索元素
    function IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
    procedure Insert(Index: Integer; Item: Pointer);                                                                //插入一个对象元素
    function Last: Pointer;                                                                                                       //当前对象指针移动到最后一个元素上
    procedure Move(CurIndex, NewIndex: Integer);                                                              //将当前对象移动位置
    function Remove(Item: Pointer): Integer; inline;                                                               //移除对象
    function RemoveItem(Item: Pointer; Direction: TDirection): Integer;
    procedure Pack;                                                                                                               //清空空对象

//TListSortCompare = function (Item1, Item2: Pointer): Integer;
   //TListSortCompareFunc = reference to function (Item1, Item2: Pointer): Integer;
    procedure Sort(Compare: TListSortCompare);                                                                //排序函数,这里TListSortCompare对应的是排序函数的指针
    procedure SortList(const Compare: TListSortCompareFunc);                                         //TListSortCompareFunc是对应TListSortCompare的匿名函数,方法定义更为灵活
    procedure Assign(ListA: TList; AOperator: TListAssignOp = laCopy; ListB: TList = nil);  //指定内容来源
    property Capacity: Integer read FCapacity write SetCapacity;                                         //空间计数
    property Count: Integer read FCount write SetCount;                                                      //元素计数
    property Items[Index: Integer]: Pointer read Get write Put; default;
    property List: TPointerList read FList;                                                                              //指针列表
  end

我们可以看到,这个TList算所有列表之源,具备了所有列表类型的基础方法属性。

b, TObjectList

这种List的单元Contnrs需要额外引用一下,我们在这个类的源码中可以看到,几乎所有的方法名跟TList都是一致的,只不过元素对象参数由TPoint变成了TObject,另外,还增加了以下两个新的方法:

constructor Create(AOwnsObjects: Boolean); overload;       //重载了一个构造方法,这里可以在创建的时候直接指定其拥有者,如果是False,就跟TList差别很大了,相当于这个ObjectList是独立于元素存在的。

//这时候元素的空间需要额外的管理

property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;   //这个是ObjectList的一个属性,可以由构造方法带进来,也可以使用时改变。

c,TComponetList

这个是直接继承TObjectList的,同样的,所有元素由基础对象改成了组件。但是这个类中也增加了一个方法:

procedure HandleFreeNotify(Sender: TObject; AComponent: TComponent);            //这个方法对应着procedure TComponent.FreeNotification(AComponent: TComponent);方法

这个方法使得其管理的对象释放更为灵活,释放一个元素组件的时候,不需要操作ComponentList ,可以直接操作元素,并通过元素组件的方法自动触发TComponentList来处理链结构。

d,TStringList

TStringList跟TList并不是一脉相承的,而是继承TStrings的,而TStrings是继承TPersistent的,其方法完全是为字串服务的,跟TList有相似点,其变化又比TList系列更为复杂。因为其具备

一系列增加和管理对象的方法:

property Objects[Index: Integer]: TObject read GetObject write PutObject;

function AddObject(const S: string; AObject: TObject): Integer; virtual;

function IndexOfObject(AObject: TObject): Integer; virtual;

procedure InsertObject(Index: Integer; const S: string; AObject: TObject); virtual;

function ToObjectArray: TArray<TObject>;

除此之外,还具备字典配对的功能:

property Names[Index: Integer]: string read GetName;

property KeyNames[Index: Integer]: string read GetKeyName;

property Values[const Name: string]: string read GetValue write SetValue;
    property ValueFromIndex[Index: Integer]: string read GetValueFromIndex write SetValueFromIndex;

这使得其功能和扩展性都显得极为强大,TStrings是个抽象类,而TStringList增加了Sort方法和对象耦合属性OwnsObjects。 当没有使用对象和字典配对的时候,TStringList看起来就象一个简单的字串数组。

e,TClassList

这个类似乎不需要额外谈的,类中类的列表形态,批量处理的情景除非是特别复杂的模型才可以用到。其继承类是TList,没有对象管理的拥有者功能。

2,泛型

泛型的出现,直接弄得各种List似乎都变成了一种兼容的特例模式了。泛型的可以选择任何类型的数据元素,并可以以任何数据结构模式进行组合。虽然在数据定义阶段略显复杂,但是作为一种强力的数据扩展

可以应用的场景也多得多。

泛型的引用单元:Generics.Collections,泛型的定义模式:

a,泛型数据类型的构成基础

我们先来看看泛型单元中的前四个数据定义,他们是泛型构成的基础件:TArray(TObject),TEnumerator<T>(TObject),TEnumerable<T>(TObject),TListHelper(TObject)

TArray = class
  private
    class procedure QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
      L, R: Integer); static;
    class procedure CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt); static;
  public
    class procedure Sort<T>(var Values: array of T); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>); overload; static;
    class procedure Sort<T>(var Values: array of T;
      const Comparer: IComparer<T>; Index, Count: Integer); overload; static;

class function BinarySearch<T>(const Values: array of T; const Item: T;
      out FoundIndex: Integer; const Comparer: IComparer<T>;
      Index, Count: Integer): Boolean; overload; static;
    class function BinarySearch<T>(const Values: array of T; const Item: T;
      out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean; overload; static;
    class function BinarySearch<T>(const Values: array of T; const Item: T;
      out FoundIndex: Integer): Boolean; overload; static; static;

class procedure Copy<T>(const Source: array of T; var Destination: array of T; SourceIndex, DestIndex, Count: NativeInt); overload; static;
    class procedure Copy<T>(const Source: array of T; var Destination: array of T; Count: NativeInt); overload; static;
  end;

这是额外为TArray定义的一段代码,本人看得不是特别懂,感觉这个主要的功能是为System中的TArray<T>定义作一个扩展。

注意,TArray<T>的定义是出现在System单元中:TArray<T> = array of T;

这个TArray扩展为后续的泛型定义,提供了一个本体。接下来,我们看看两个抽象类:TEnumerator<T>,TEnumerable<T>.

TEnumerator<T> = class abstract
  protected
    function DoGetCurrent: T; virtual; abstract;
    function DoMoveNext: Boolean; virtual; abstract;
  public
    property Current: T read DoGetCurrent;
    function MoveNext: Boolean;
  end;

TEnumerable<T> = class abstract
  private
  {$HINTS OFF}
    function ToArrayImpl(Count: Integer): TArray<T>; // used by descendants
  {$HINTS ON}
  protected
    function DoGetEnumerator: TEnumerator<T>; virtual; abstract;
  public
    destructor Destroy; override;
    function GetEnumerator: TEnumerator<T>;
    function ToArray: TArray<T>; virtual;
  end;

这两个抽象类,TEnumerable是所有泛型的基类,定义出泛型的数据实体是TArray<T>模式,并且引用了另外一个抽象方法类TEnumerator ,使得泛型具备获取当前元素Current以及MoveNext导航功能。

这个设计很重要,我们可以看到Current和MoveNext在这里不再是数据结构的属性,而是作为元素基础功能出现的。

最后,我们再来看看一个附加的结构体:TListHelper = record ,它十分复杂,我没有太多时间去详细研究,暂时看到它是作为泛型的扩展属性使用的,所以就认为它是一个泛型的帮助信息扩展吧。

b,TList<T>

这个类型的篇幅还是比较长的,比TList要复杂多了,既融合了TList的基础定义,又加入了泛型的实现基础,下面我们一起看一看其定义的过程。

TList<T> = class(TEnumerable<T>)
  private type
    arrayofT = array of T;                                                                                           //定义了一个内部元数组类
  var
    FListHelper: TListHelper; // FListHelper must always be followed by FItems     //暂且认为是帮助信息类,不做过多分析
    FItems: arrayofT; // FItems must always be preceded by FListHelper                //利用元数组类实现了一个元数据实体
    FComparer: IComparer<T>;                                                                               //为排序而诞生的比较方法指针
    FOnNotify: TCollectionNotifyEvent<T>;                                                             //内部事件

function GetCapacity: Integer; inline;                                                                 //得到整个泛型的内存空间
    procedure SetCapacity(Value: Integer); overload; inline;                                  //动态设置元素的Length
    procedure SetCount(Value: Integer); inline;                                                      //动态设置元素个数
    function GetItem(Index: Integer): T; inline;                                                        //根据序号获得指定元素
    procedure SetItem(Index: Integer; const Value: T); inline;
    procedure GrowCheck(ACount: Integer); inline;                                              //Helper相关
    procedure DoDelete(Index: Integer; Notification: TCollectionNotification); inline;      //根据序号删除并销毁某元素
    procedure InternalNotify(const Item; Action: TCollectionNotification);                      
    function InternalCompare(const Left, Right): Integer;
    property FCount: Integer read FListHelper.FCount write FListHelper.FCount;
  protected
    function ItemValue(const Item: T): NativeInt;                                                 //返回元素的值,NativeInt是内存中一种Int编码值。
    function DoGetEnumerator: TEnumerator<T>; override;                               //重新构建元素的导航功能。
    procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
  public
  type
    TDirection = System.Types.TDirection;                                                        //定义方向,用于List的定向操作
    TEmptyFunc = reference to function (const L, R: T): Boolean;                    //为空时的匿名函数
    TListCompareFunc = reference to function (const L, R: T): Integer;            //为排序比较时的匿名函数

//再往下看基本就没什么新方法了,功能都是结合TList和TEnumerable的功能重组.

constructor Create; overload;
    constructor Create(const AComparer: IComparer<T>); overload;
    constructor Create(const Collection: TEnumerable<T>); overload;
    destructor Destroy; override;

class procedure Error(const Msg: string; Data: NativeInt); overload; virtual;
{$IFNDEF NEXTGEN}
    class procedure Error(Msg: PResStringRec; Data: NativeInt); overload;
{$ENDIF  NEXTGEN}

function Add(const Value: T): Integer; inline;

procedure AddRange(const Values: array of T); overload;
    procedure AddRange(const Collection: IEnumerable<T>); overload; inline;
    procedure AddRange(const Collection: TEnumerable<T>); overload; inline;

procedure Insert(Index: Integer; const Value: T); inline;

procedure InsertRange(Index: Integer; const Values: array of T); overload;
    procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
    procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;

procedure Pack; overload;
    procedure Pack(const IsEmpty: TEmptyFunc); overload;

function Remove(const Value: T): Integer; inline;
    function RemoveItem(const Value: T; Direction: TDirection): Integer; inline;
    procedure Delete(Index: Integer); inline;
    procedure DeleteRange(AIndex, ACount: Integer); inline;
    function ExtractItem(const Value: T; Direction: TDirection): T; inline;
    function Extract(const Value: T): T; inline;

procedure Exchange(Index1, Index2: Integer); inline;
    procedure Move(CurIndex, NewIndex: Integer); inline;

function First: T; inline;
    function Last: T; inline;

procedure Clear; inline;

function Expand: TList<T>; inline;

function Contains(const Value: T): Boolean; inline;
    function IndexOf(const Value: T): Integer; inline;
    function IndexOfItem(const Value: T; Direction: TDirection): Integer; inline;
    function LastIndexOf(const Value: T): Integer; inline;

procedure Reverse; inline;

procedure Sort; overload;
    procedure Sort(const AComparer: IComparer<T>); overload;
    function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
    function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;

procedure TrimExcess; inline;

function ToArray: TArray<T>; override; final;

property Capacity: Integer read GetCapacity write SetCapacity;
    property Count: Integer read FListHelper.FCount write SetCount;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
    property List: arrayofT read FItems;

property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;

type                                                                                                         //这里重新指定了元素导航的功能实现
      TEnumerator = class(TEnumerator<T>)
      private
        FList: TList<T>;
        FIndex: Integer;
        function GetCurrent: T;
      protected
        function DoGetCurrent: T; override;
        function DoMoveNext: Boolean; override;
      public
        constructor Create(const AList: TList<T>);
        property Current: T read GetCurrent;
        function MoveNext: Boolean;
      end;

function GetEnumerator: TEnumerator; reintroduce; inline;
  end;

该类应该是泛型中使用最为广泛的一个类,我们既可以用以后的类来组合使用,又可以重新定义其各项基础功能实现扩展。

直接使用的模式: DataSetList: TList<TDataSet>;

重新定义的模式:

type

TSpecList<T>=class(TList<T>)

....

end;

使用的时候直接将<T>实化:DataSetList: TSpecList<TDataSet>;

c,其他几种使用频率比较高的泛型:

TQueue<T> = class(TEnumerable<T>)                           //队列泛型,定义几乎跟TList<T> 一样,所以这里的方法说明省去。

TThreadList<T> = class                                                   //线程泛型,实体是TList<T>,针对其控制增加了锁定方法。

TStack<T> = class(TEnumerable<T>)                            //堆栈泛型,增加了Pop和Push方法,其他定义几乎跟TList<T>一致。

TPair<TKey,TValue> = record
    Key: TKey;
    Value: TValue;
    constructor Create(const AKey: TKey; const AValue: TValue);
  end;
  TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)      //字典泛型,这个比较有用,数据是以Key和Value成对出现。主要是增加了Hash方法,各种元素操作也都以Key作为参数。

这些泛型都是基于数据结构的变化。

d,与对象相关的泛型扩展 TObjectList<T>,

TObjectList<T: class> = class(TList<T>)

private
    FOwnsObjects: Boolean;
  protected
    procedure Notify(const Value: T; Action: TCollectionNotification); override;
  public
    constructor Create(AOwnsObjects: Boolean = True); overload;
    constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
    constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
    destructor Destroy; override;
    property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;                                         //主要就是增加了这个属性,让其元素耦合性降低
  end;

TObjectQueue<T: class> = class(TQueue<T>)

TObjectStack<T: class> = class(TStack<T>)

TObjectDictionary<TKey,TValue> = class(TDictionary<TKey,TValue>)

以上这四种泛型都是在原有泛型上的轻微扩展,同列表的对象扩展一样。最主要的属性就是OwnsObjects,使得整个泛型数据集,可以拥有对象空间的独立管理能力。

3,小结

为什么我们要使用泛型?泛型数据的优势和劣势又各是什么呢?

其实Delphi引用泛型数据算比较落后的了,Java很早就有泛型概念,而FrameWork也是从2.0 开始就引入了泛型数据,而Delphi是从Delphi2009~Delphi2010才正式引入泛型。

泛型的早期模式,其实就是各种列表,也就是本篇的第1点所阐述的内容,对比泛型和列表,其实泛型能实现的方式列表都可以实现,而列表的异构元素结构,泛型是不适合的。

那么泛型相对列表有什么优势呢?优势主要体现在两个方面:重用性,安全高效性。

a,重用性

这里举个例子说明,我们如果需要两个列表TStringxxxList,TIntxxxList,如果用列表继承的概念,那就必须要写两个定义:

type TStringList=class(TList)

...这可能会有count方法

end;

type TIntxxxList=class(TList)

...这可能会有count方法

end;

如果换作泛型,就只需要定义一次就好了,列表中通性的方法是固定的。

type TxxxList<T>=class(TList<T>)

...这里可能有count方法

end;

使用时,我们用TxxxList<string>,TxxxList<Int>就可以取代两种List。

b,安全高效性

虽然用列表也可以实现子类型的存取,但是在使用过程中就免不了要进行类型转换和判断(装箱和拆箱),即不安全,也会影响到系统效率。

例如:

AllDataSets : TComponentList;                                 //用List进行一个数据集的存储。

AllDataSets := TComponentList.Create(False);        //非耦合性列表
  AllDataSets.Add(ADataSet);                                   //存放一个数据集

到这一步似乎跟泛型都没什么差异,然而取的时候就比较麻烦了。

if AllDataSets.Items[ADataSetNo] is TDataSet then

funxxx(AllDataSets.Items[ADataSetNo] as TDataSet);

这不仅仅意味着要承受各种非规则数据的干扰,还必须进行强制类型转换,才能完成其初期设计的【数据集列表】这样的概念。反观泛型就要简单得多:

定义:AllDataSets : TObjectList<TDataSet>;

AllDataSets := TObjectList<TDataSet>.Create(False);

AllDataSets.Add(ADataSet);

我们在使用中,完全不担心类型问题,直接调用就好了,而且即便真的有类型匹配的错误,在编译期就可以将其呈现出来。

看看Delphi中的列表(List)和泛型的更多相关文章

  1. Delphi中使用比较少的一些语法

    本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ---Murphy 1,构造和析构函数: a,构造函数: 一般基于TComponent组件的派生类 ...

  2. Delphi中的异常处理

    转载:http://www.cnblogs.com/doit8791/archive/2012/05/08/2489471.html 以前写Delphi程序一直不注意异常处理,对其异常处理的机制总是一 ...

  3. Delphi中线程类TThread实现多线程编程2---事件、临界区、Synchronize、WaitFor……

    接着上文介绍TThread. 现在开始说明 Synchronize和WaitFor 但是在介绍这两个函数之前,需要先介绍另外两个线程同步技术:事件和临界区 事件(Event) 事件(Event)与De ...

  4. Delphi中如何将 Exe 程序或其他资料打包在内,使用时再释放使用(转)

    1.生成一个rc文件,文件格式如下: rname exefile "test.exe" //rname是资源名称 //exefile是资源类型 //text.exe是资源 资源类型 ...

  5. Delphi中编辑word

      其他(28)   //启动Word   try     wordapplication1.connect;   except     messagedlg('word may not be ins ...

  6. [转]Delphi中ShellExecute的妙用

    Delphi中ShellExecute的妙用       ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件.打开一个目录.打印一个文件等等),并对外部程序有一定的控制.   ...

  7. Delphi中停靠技术的实现

    随着软件技术的不断进步,软件界面也越来越美观,操作也越来越方便.综观市面上比较专业的各种软件,我们会发现大部分都提供窗体停靠的功能,特别象工具软件,基本上都或多或少有停靠功能.自然,Delphi也支持 ...

  8. Delphi 的运算符列表,运算符及优先级表格 good

    Delphi 的运算符列表 分类 运算符 操作 操作数 结果类型 范例 算术运算符 + 加 整数,实数 整数,实数 X + Y - 减 整数,实数 整数,实数 Result - 1 * 乘 整数,实数 ...

  9. Delphi中的“委托”

    .NET中有委托(Delegate)的概念,其声明形式如下所示:     public delegate void MyDelegate(int aIntParam, string aStringPa ...

  10. DELPHI语法基础学习笔记-Windows 句柄、回调函数、函数重载等(Delphi中很少需要直接使用句柄,因为句柄藏在窗体、 位图及其他Delphi 对象的内部)

    函数重载重载的思想很简单:编译器允许你用同一名字定义多个函数或过程,只要它们所带的参数不同.实际上,编译器是通过检测参数来确定需要调用的例程.下面是从VCL 的数学单元(Math Unit)中摘录的一 ...

随机推荐

  1. Jenkins基础系统之完整的.net项目编译

    一.目标 搭建jenkins服务器以及配置一台.net编译的slave客户端 完整跑通一个asp.net项目的发布 二.搭建jenkins环境 2.1 安装jenkins 1. 根据官网提示安装 进入 ...

  2. iOS 录音,获取录音时长及格式转换

    转载请注明出处!!! 在APP中,我们也会遇到调用录音的功能,那么如何录音呢?并且在iOS中录音格式是wav或者caf格式的,和安卓不通用,为了达到通用的效果,我们还需要把他转换成通用格式.近期我遇到 ...

  3. 从 url 到 PPT 一键生成:Coze 工作流,颠覆你的内容创作方式!

    完整内容:从 url 到 PPT 一键生成:Coze 工作流,颠覆你的内容创作方式! 你是否曾在面对大量文章资料,却要在短时间内将其精华提炼并制作成演示文稿时,感到焦头烂额.无从下手?一页页翻阅文章, ...

  4. [开源免费] iGTTS(Gemini TTS) 文本转语音(TTS)的命令行工具。

    iGTTS(Gemini TTS) iGTTS(Gemini TTS) 开源免费的文本转语音(TTS)的命令行工具. iGTTS(Gemini TTS) 是通过调用 Gemini TTS 的接口,实现 ...

  5. FlashAttention逐代解析与公式推导

    Standard Attention 标准Attention计算可以简化为: \[O = softmax(QK^T)V \tag{1} \] 此处忽略了Attention Mask和维度归一化因子\( ...

  6. VU9P板卡设计方案:565-基于VU9P的32@ SFP28+4@ QSFP28路光纤交换板卡

    .板卡概述 板卡基于Xilinx FPGA VU9P 设计的一款32路SFP28+4路QSFP28的光纤交换板卡,用于以太网的交换功能的验证. 二.板卡原理框图 三.板卡主要性能 ● 主芯片:选用 X ...

  7. P9041 [PA2021] Fiolki 2

    P9041 [PA2021] Fiolki 2 题意 给一个 \(n\) 个点 \(m\) 条边的 DAG 和一个常数 \(k\). 定义 \(f(l,r)\) 表示最多选择不相交路径条数,满足起点 ...

  8. Qwen WebAgent 系列

    GitHub地址: https://github.com/Alibaba-NLP/WebAgent# 共有5篇系列文章 为Agent(React架构)在web search(Deepsearch)提供 ...

  9. 【ubuntu】ubuntu 20.04安装docker,使用nginx部署前端项目,nginx.conf文件配置

    文章目录 一.安装docker 1.将apt升级到最新 2.使用apt安装 docker 和 docker-compose (遇到提示输入`y`) 3.将当前用户添加到docker用户组 4.运行he ...

  10. 常见问题处理 --- win卡任务栏 设置无法打开 桌面重启

    解决方法 下载autoruns在微软官网 https://learn.microsoft.com/en-us/sysinternals/downloads/ 打开后找到explore 取消所有黄色的勾 ...