> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ss14.art/llms.txt
> Use this file to discover all available pages before exploring further.

# Типы

Как может следовать из вывода команд `explain` и `help`, Toolshed — это строго типизированный язык. Система типов, **по большей части**, соответствует C#, хотя toolshed добавляет некоторые дополнительные правила типов для удобства как пользователей, так и разработчиков. То есть вывод команд — это реальные C#-типы, такие как `int`, `EntityUid` или какой-нибудь `IEnumerable<T>`, а не просто строки. Все команды имеют сигнатуру типа, и эта сигнатура может динамически изменяться в зависимости от типа переданного значения.

Например, тип, переданный в команду сложения `+`, определяет тип вывода и способ парсинга аргумента.
Например, `i 1 + 2` и `f 1 + 2.5` — валидные команды, но `i 1 + 1.5` не сможет распарсить "1.5" как int-аргумент.

```
> explain i 1 + 1

i - Целочисленная константа.
Pipe input: [none]
Pipe output: Int32
Signature:
  i <value (Int32)>

+ - Выполняет числовое сложение.
Pipe input: Int32
Pipe output: Int32
Signature:
  <x> → + <y (Int32)>

> explain f 1 + 1.5

f - Константа с плавающей точкой.
Pipe input: [none]
Pipe output: Single
Signature:
  f <value (Single)>

+ - Выполняет числовое сложение.
Pipe input: Single
Pipe output: Single
Signature:
  <x> → + <y (Single)>

> i 1 + 1.5

i 1 + 1.5
      ^^^
The value 1.5 is not a valid Int32.
```

## Аргументы типа

Некоторые аргументы команд также принимают **аргументы типа**. Эти аргументы обычно определяют тип вывода или способ парсинга других аргументов. **Аргументы типа** всегда указываются перед любыми другими аргументами, но в остальном выглядят как обычные аргументы. В сигнатурах команд `help` и `explain` они отображаются как часть имени команды, используя синтаксис C# generics, т.е. `<T>`, `<T1, T2>`.

Например, команда `comp:get<T>` имеет сигнатуру `IEnumerable<EntityUid> -> IEnumerable<T>`, где T — любой указанный пользователем компонент. Фактический тип компонента указывается через **аргумент типа**:

```
> help comp:get

comp:get - Получает указанный компонент из указанной сущности.
Usage:
  <input (IEnumerable<EntityUid>)> → comp:get<T> → IEnumerable<T>
  <input (EntityUid)> → comp:get<T> → T


> explain entities comp:get Item

entities - Возвращает все сущности на сервере.
Pipe input: [none]
Pipe output: IEnumerable<EntityUid>
Signature:
  entities

comp:get - Получает указанный компонент из указанной сущности.
Pipe input: IEnumerable<EntityUid>
Pipe output: IEnumerable<ItemComponent>
Signature:
  <input> → comp:get<ItemComponent>
```

## Для пользователей

### Все значения — это список длиной 1 (`T -> IEnumerable<T>`)

Toolshed автоматически преобразует одиночное значение в список, содержащий только это значение, если необходимо. Это позволяет применять команды, работающие только с перечислениями, к одиночным значениям.

### Любая коллекция T — это `IEnumerable<T>`

Технически это не специфика toolshed, но полезно знать, что можно использовать `List<T>`, `HashSet<T>`, `Dictionary<K,V>` и т.д. как вход для любой команды, принимающей перечисление.

### `IEnumerable<T>` упаковывается в `List<T>` при присваивании

При присваивании перечисления переменной Toolshed автоматически преобразует его в список для полного вычисления и возможности повторного использования.
В C# использование `IEnumerable<T>` более одного раза запрещено, отсюда и это преобразование.

## Для разработчиков

### Ограничения ковариантности и контравариантности

Toolshed отказывается выполнять сложные проверки присваиваемости для типов с более чем одним ковариантным или контравариантным аргументом, чтобы избежать комбинаторного взрыва при поиске всех возможных типов для использования.

### `IAsType<T>` и неявное приведение

Toolshed для любого типа, реализующего `IAsType<T>`, будет считать T валидным неявным приведением для этого типа.
Например, если `Foo : IAsType<Bar>`, Toolshed использует реализацию IAsType для получения Bar из Foo, если это позволит успешно проверить типы при выполнении команды.
