# 自定类型

## 什么是自定类型？ <a href="#what-are-they" id="what-are-they"></a>

**自定类型是你最好的朋友。**&#x5B83;被用于创建拥有相同参数的对象的“集合”，并且快速轻松地进行交互。

> 想象一下《太空入侵者》，现在屏幕上有很多的外星人。每一个外星人都有一些需要的变量：x、y 和一个控制画面显示的变量（腿向外或向内）。
>
> 现在，我们可以创建数百个变量，例如 `invader1x`、`invader1y`、`invader2x`、`invader2y` 来控制所有的外星人。但是这没多大意义，不是吗？你可以用数组来储存它们，并且使用 `For ... Next` 循环，但是这太麻烦了！
>
> “自定类型变量集合”就是用来解决这种问题的。

`Type` 能够定义一个对象集合。每个对象都会获得类型中 `Field` 定义的变量的副本。集合中每个对象的每个变量都可以单独读取，并且可以快速迭代。使用 `Field` 命令在 `Type` 和 `End Type` 中间定义所需的变量。

如果有帮助的话，您可以将类型集合想象成一个数据库。每个对象都是数据库的记录，每个变量都是记录中的字段。使用 `Before`、`After` 和 `For ... Each` 命令，您可以移动“数据库”的指针来指向不同的记录，以检索并设置变量的字段值。

> 不是数据库专家？还需要举个例子？没问题。想象你正在为一场演讲或一次活动搭建场景，你将要为观众摆数百把椅子。
>
> 椅子必须要放在地板上的某个地方，而有些椅子会比其他椅子高一点（比如老板和市长的椅子）。所以，作为电脑天才，你正在想办法最快最好地来布置椅子。
>
> 你意识到地板是方格的，地板完全是一个巨大的网格！弄这事更简单了！你只需要在一张图纸上对地板进行编号，并根据老板告诉你的重要人物的座位，将每张椅子的高度写到网格表上。
>
> 所以，每把椅子有会有一个 x 和 y，并会有一个水平高度来表示椅子的高度（height）。很好，我们逻辑很清晰。现在，尽管我们把这些东西都写在图纸上了，我们仍旧需要自己去放椅子。
>
> 当你完成之后，你的老板走到你面前说：“它们没有居中，把它们向右平移一米。”我操！本来这些东西都很完美。尽管椅子右移一米这事不难（毕竟它们的高度和顺序不会改变），但是你仍旧要一把一把挪这些椅子！
>
> 如果你能挥挥手说：“房间里的椅子的 x 都增加一个方格”，然后它们奇迹的挪过去了，那就太棒了。但是现实是——这些椅子都要你自己搬！

在 Blitz 中，你可以设置一个叫做 `Chair` 的类型，然后将类型的字段（Field）设置为 `x`、`y` 和 `height`。您可以使用 `New` 命令来创建所需数量的椅子（每次调用 `New` 时，它都会生成一把带有属于自己的 `x`、`y` 和 `height` 的新的椅子），并为他们分配由您决定的 `x`、`y` 和 `height`。

在上面的例子中，当老板让你把椅子挪动一格的时候，你可能会叫苦连天——这活可不少！但是在 Blitz 中，我们可以用四行代码让所有的 `Chair` 对象调整到新位置（利用 `For ... Each` 命令）。

## 定义自定类型 <a href="#defining-a-type" id="defining-a-type"></a>

使用 `Type` 关键字定义自定类型，例如：

```basic
Type MyType 
    Field x, y 
End Type
```

这将创建一个名为 `MyType` 的自定类型，其中包括两个字段：`x` 和 `y`。

自定类型的字段可以是任意基本数据类型，也可以是任意自定类型。类型标签可以用于确定字段的类型，例如：

```basic
Type MyType 
    Field x, y               ; 整数值
    Field description$       ; 字符串 
    Field delta_x#, delta_y# ; 浮点值
End Type 
```

## 创建自定类型实例 <a href="#creating-a-type-instance" id="creating-a-type-instance"></a>

您可以在创建变量或数组的名称之后用 “`.`+类型名称”的方式创建自定类型的变量或数组。例如：

```basic
Global mine.MyType
Dim all_mine.MyType(100)
```

在使用自定类型变量或数组元素之前，必须使用 `New` 运算符对其进行初始化。例如：

```basic
mine.MyType = New MyType
```

`New` 运算符将创建一个类型为 MyType 的“对象”，并返回创建的对象的“指针”。`New` 运算符后面的标识符必须是有效的自定类型名称。

自定类型中的字段可以通过“`\`”字符访问。例如：

```basic
mine\x=100
Print mine\x
```

## 销毁自定类型实例 <a href="#destroying-a-type-instance" id="destroying-a-type-instance"></a>

当您不再需要一个对象的时候，您应该使用 `Delete` 命令将其删除。例如：

```basic
Delete mine
```

这将释放对象所使用的内存。

## 检测是否存在 <a href="#determining-existance" id="determining-existance"></a>

特殊关键字 `Null` 被用于表示不存在的对象。如果对象尚未用 `New` 进行初始化，或者已被 `Delete` 进行删除，则该对象不存在。例如：

```basic
mine.MyType = New MyType 
If mine <> Null 
     Print "exists!" ; 存在！
Else 
     Print "doesn't exist!" ; 不存在！
EndIf 
Delete mine 
If mine <> Null 
     Print "exists!" ; 存在！
Else 
     Print "doesn't exist!" ; 不存在！
EndIf 
```

...就会打印：

```
exists! 
doesn't exist!
```

每个自定类型都有一个属于自己的对象列表，称为“类型列表”。使用 `New` 创建对象时，创建的对象将自动添加到类型列表中。使用 `Delete` 释放对象时，对象将从列表中移除。类型列表是动态的——一旦实例被销毁，它在集合中就会被删除，其他的对象就会在集合中“上移”。

## 类型列表迭代 <a href="#iteration-through-type-lists" id="iteration-through-type-lists"></a>

`First`、`Last`、`After` 和 `Before` 运算符允许您访问类型列表。`First` 运算符会返回类型列表开头的对象。例如：

```basic
mine.MyType = First MyType
```

这将为 `mine.MyType` 赋值自定类型 MyType 的类型列表中的第一个对象。

同理，`Last` 会返回列表末尾的对象。

如果类型列表为空，则 `First` 和 `Last` 将会返回 `Null`。

您可以使用 `After` 查找一个对象之后的对象，使用 `Before` 查找一个对象之前的对象。例如：

```basic
mine.MyType = First MyType ; mine=类型列表的第一个对象
mine = After(mine) ; mine=第二个对象
mine = After(mine) ; mine=第三个对象
mine = Before(mine) ; mine=第二个对象
mine = Before(mine) ; mine=又是第一个！
```

如果类型列表中找不到对象，`After` 和 `Before` 将返回 `Null`。例如：

```basic
mine.MyType = Last MyType ; mine=最后一个对象
mine = After(mine) ; 最后一个后面没有对象！
```

使用 `New` 创建对象时，默认情况下，该对象将会放置在其类型列表的末尾。然而，您可以使用 `Insert` 来在类型列表中移动对象。

```basic
mine1.MyType = New MyType
mine2.MyType = New MyType 
Insert mine2 Before mine1
```

这将会把 `mine2` 对象插入 `mine1` 之前。您也可以使用 `After` 在其之后插入，而不是用 `Before`。

以下是将对象移动到类型列表开头的示例：

```basic
Insert mine Before First MyType
```

一种特殊形式的 `For ... Next` 允许您轻松遍历列表中的所有对象。例如：

```basic
For mine.MyType = Each MyType 
    ...
Next
```

这会让变量 `mine.MyType` 循环赋值为 MyType 列表中的所有对象。

最后，`Delete Each` 命令允许您删除特定类型列表中的所有对象。例如：

```basic
Delete Each MyType
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.ziyuesinicization.site/blitz-basic-language-reference/zh_hans/custom-types.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
