跳转到内容

Sway 参考手册/数组和列表

来自维基教科书,开放世界中的开放书籍

Sway 内置了三种主要的数据结构数组列表对象。数据结构只是一个信息位[1]集合,它们以某种方式粘合在一起形成一个整体。这些位中的每一个都可以单独访问。通常,这些位之间也存在某种关系,因此数据结构是将所有这些相关位打包在一起的便捷方式。

数组是一种数据结构,它具有以下属性:每个信息位都可以像其他位一样快速访问。要创建数组,可以使用array函数

   var a = array(42,64.0,"hello",:world);

此调用将创建一个数组,将四个项目或元素打包在一起。变量a被创建并设置为指向该包。

要访问单个元素,可以使用“方括号”表示法或“点”表示法。例如,以下是如何访问数组中的第一个项目

   sway> a[0];
   INTEGER: 42
    
   sway> a . 0
   INTEGER: 42

注意,数组索引(方括号之间或点后的数字称为索引)是从零开始的。也就是说,第一个元素位于索引 0,第二个元素位于索引 1,依此类推。通常,由于“点”的高优先级,不会将“点表示法”用于数组。例如

   a[row * cols + col]

与以下内容不同

   a . row * cols + col

在后者中,检索row索引处的元素,然后乘以cols,最后将该数字加到col。为了使后者与前者相同,需要对索引计算进行括号化

   a . (row * cols + col)

使用方括号表示法,括号化会自动执行。

也可以对数组进行赋值

   sway> a[0] = :forty-two;
   SYMBOL: :forty-two
    
   sway> a[0];
   SYMBOL: :forty-two

您也可以查看数组的尾部。数组的尾部是没有第一个元素或头部元素的数组。

   sway> tail(a);
   ARRAY: [64.000000000,"hello",:world]
    
   sway> tail(a)[0];
   REAL_NUMBER: 64.000000000

如果不断取数组的尾部,最终会得到:null:

   sway>tail(tail(tail(tail(a))));
   SYMBOL: :null;

分配空数组

[编辑 | 编辑源代码]

可以分配一个数组,而无需指定实际元素

   var b = alloc(10);

这将创建一个包含十个元素的数组(索引范围从零到九)。

   sway> b[0];
   SYMBOL: :null;

每个元素都初始化为 :null。

列表是一种数据结构,它具有以下属性:可以通过在列表中的任何位置添加或删除元素来延长或缩短它。这种灵活性的折衷方案是,列表中较后面的元素比较前面的元素需要更长时间访问。创建和访问列表中的元素与数组非常相似

   var a = list(42,64.0,"hello",:world);
    
   sway> a[2];
   STRING: "hello"
   
   sway> a[3] = 13;
   INTEGER: 13

要使列表变长,可以轻松地将一个元素添加到现有列表的前面,以创建一个新列表

   var b = "apple" join a;
   LIST: ("apple",42,64.000000000,"hello",:world)

列表可以共享元素

[编辑 | 编辑源代码]

需要注意的是,上面的ab共享元素,对a的更改将影响b

   sway> a[1] = :pie;
   SYMBOL: :pie
    
   sway> a;
   LIST: (42,:pie,"hello",:world);
    
   sway> b;
   LIST: ("apple",42,:pie,"hello",:world);

使b独立于a是一项看起来比实际更简单的任务。以下是一个尝试执行此操作的函数

   function join*(item,items)
       {
       function copy(stuff)
           {
           if (stuff == :null,:null,stuff[0] join copy(tail(stuff)));
           }
       item join copy(items);
       }

这在某些情况下有效

   var x = list(:apples,:pears,:bananas);
   var y = :kumquats join* x;               //note join*, not join
   
   x[1] = :persimmons;
   sway> x;
   LIST: (:apples,:persimmons,:bananas);
    
   sway> y;
   LIST: (:kumquats,:apples,:pears,:bananas);

问题在于,join*进行的复制是浅复制。也就是说,复制了传入的列表,但没有复制元素。对于符号列表,不需要复制元素,但这并非总是如此

   var m = list(2,3,4);
    
   sway> var p = list(1,m,5);
   LIST: (1,(2,3,4),5)
   sway> var q = 0 join* p;       // note, join*, not join
   LIST: (0,1,(2,3,4),5)

到目前为止,您理解了吗?不仅q共享p的元素,它们还共享m的元素。考虑以下操作

   p[1][1] = 333; 

我们更改了p的第一个元素的第一个元素

   sway> p;
   LIST: (1,(2,333,4),5)
    
   sway> q;
   LIST: (0,1,(2,333,4),5)

通过p进行的更改仍然更改了q。要解决这个问题,需要进行深复制,其中复制列表的元素,并复制元素的元素,依此类推。

更改列表的尾部

[编辑 | 编辑源代码]

可以使用tail=函数更改列表的尾部

   var a = list(1,2,3);
    
   a tail= list(222,333);
   sway> a;
   LIST: (1,222,333);

您可以在任何类型的列表上使用tail=,即使是通过tail生成的列表

   var b = list(1,2,3);
    
   tail(b) tail= list(333);
   sway> b;
   LIST: (1,2,333);

插入到列表中间

[编辑 | 编辑源代码]

可以使用join、tail和tail=的组合将元素插入列表中间。以下是如何在第一个元素之后插入一个项目

   var c = list(1,3,4);
   c tail= (3 join tail(c));
   sway> c;
   LIST: (1,2,3,4);

需要括号来确保c的尾部没有设置为数字 3,并且结果与c的尾部连接在一起。

这种插入方法会更改原始列表。也可以通过编写插入函数来创建一个包含插入元素的新列表

   function insert(item,items,index)
       {
       if (index == 0)
           {
           item join items; //put the item at the head of the list
           }
       else
           {
           items[0] join insert(item,tail(items),index - 1);
           }
       }
   var d = list(1,3,4);
   var e = insert(2,d,1); //insert at the second element
   sway> d;
   LIST: (1,3,4);
   sway> e;
   LIST: (1,2,3,4);

请注意,insert组合了插入元素之前的元素的浅复制,并创建了插入元素之后元素的共享。

将在下一章中讨论对象。

  1. 非正式意义上的位,而不是零和一。


输入和输出 · 对象

华夏公益教科书