# 6.2 通用类型 (Generic Types)

### 基本 (Basics)

In Sway, generic types follow a very similar pattern to those in Rust. Let's look at some example syntax, starting with a generic function:

在Sway中，通用类型与Rust中的模式非常相似。让我们看看一些例子的语法，从一个通用函数开始：

```
fn noop<T>(argument: T) -> T {
    argument
}

```

Here, the `noop()` function trivially returns exactly what was given to it. `T` is a *type parameter*, and it says that this function exists for all types T. More formally, this function could be typed as:

在这里，`noop()`函数单纯地返回给它的东西。`T`是一个 *类型参数*，它说这个函数对所有类型的T都存在。更正式地说，这个函数可以被写成：

```
noop :: ∀T. T -> T

```

Generic types are a way to refer to types *in general*, meaning without specifying a single type. Our `noop` function would work with any type in the language, so we don't need to specify `noop(argument: u8) -> u8`, `noop(argument: u16) -> u16`, etc.

一般来说，通用类型是一种指代类型的方式，意思是不需要指定单一类型。我们的 `noop`函数对语言中的任何类型都有效，所以我们不需要指定 `noop(参数: u8) -> u8`，`noop(参数: u16) -> u16`，等等。

### 代码生成 (Code Generation)

One question that arises when dealing with generic types is: how does the assembly handle this? There are a few approaches to handling generic types at the lowest level. Sway uses a technique called [monomorphization](https://en.wikipedia.org/wiki/Monomorphization). This means that the generic function is compiled to a non-generic version for every type it is called on. In this way, generic functions are purely shorthand for the sake of ergonomics.

在处理通用类型时，出现的一个问题是：汇编如何处理这个问题？有几种方法可以在最底层处理通用类型。Sway使用一种叫做[单形态化 monomorphization](https://en.wikipedia.org/wiki/Monomorphization)的技术。这意味着，对于每一个被调用的类型，泛型函数被编译成非泛型版本。这样一来，泛型函数就纯粹是为了人机工程学的目的而进行的速记。

### 特质约束 (Trait Constraints)

> **Note** Trait constraints [have not yet been implemented](https://github.com/FuelLabs/sway/issues/970)\
> **注意**特质约束[尚未实现](https://github.com/FuelLabs/sway/issues/970)

Important background to know before diving into trait constraints is that the `where` clause can be used to specify the required traits for the generic argument. So, when writing something like a `HashMap` you may want to specify that the generic argument implements a `Hash` trait.

在深入研究特质约束之前，需要了解的重要背景是，`where`子句可以用来指定通用参数所需的特质。因此，当编写像 `HashMap`这样的东西时，你可能想指定泛型参数实现`Hash`特质。

```
fn get_hashmap_key<T>(Key : T) -> b256
    where T: Hash
{
    // Code within here can then call methods associated with the Hash trait on Key
}

```

Of course, our `noop()` function is not useful. Often, a programmer will want to declare functions over types which satisfy certain traits. For example, let's try to implement the successor function, `successor()`, for all numeric types.

当然，我们的`noop()`函数是没有用的。通常情况下，程序员会想在满足某些特征的类型上声明函数。例如，让我们尝试为所有数字类型实现继任函数`successor()`。

```
fn successor<T>(argument: T)
    where T: Add
{
    argument + 1
}

```

Run `forc build`, and you will get:

运行`forc build`，你会得到：

```
.. |
 9 |   where T: Add
10 |   {
11 |       argument + 1                                        
   |                  ^ Mismatched types: expected type "T" but saw type "u64"
12 |   }
13 |

```

This is because we don't know for a fact that `1`, which in this case defaulted to `1u64`, actually can be added to `T`. What if `T` is `f64`? Or `b256`? What does it mean to add `1u64` in these cases?

这是因为我们不知道`1`，在这种情况下默认为`1u64`，实际上可以添加到`T`。如果`T`是`f64`呢？或者`b256`？在这些情况下，添加`1u64`是什么意思？

We can solve this problem with another trait constraint. We can only find the successor of some value of type `T` if that type `T` defines some incrementor. Let's make a trait:

我们可以用另一个特征约束来解决这个问题。我们只有在`T`类型定义了一些递增器的情况下才能找到`T`类型的某个值的继承者。让我们做一个特质：

```
trait Incrementable {
    /// Returns the value to add when calculating the successor of a value.
    fn incrementor() -> Self;
}

```

Now, we can modify our `successor()` function:

现在，我们可以修改我们的`successor()`函数：

```
fn successor<T>(argument: T)
    where T: Add,
          T: Incrementable
{
    argument + T::incrementor()
}

```

### 通用的结构和枚举 (Generic Structs and Enums)

Just like functions, structs and enums can be generic. Let's take a look at the standard library version of `Option<T>`:

就像函数一样，结构体和枚举也可以是通用的。让我们来看看标准库中的`Option<T>`：

```
enum Option<T> {
    Some: T,
    None: (),
}

```

Just like an unconstrained generic function, this type exists for all (∀) types `T`. `Result<T, E>` is another example:

就像无约束泛型函数一样，这种类型存在于所有（∀）类型`T`。`Result<T, E>`是另一个例子：

```
enum Result<T, E> {
    Ok: T,
    Err: E,
}

```

Both generic enums and generic structs can be trait constrained, as well. Consider this struct:

泛型枚举和泛型结构也都可以被特质约束。考虑一下这个结构：

```
struct Foo<T>
    where T: Add
{
    field_one: T,
}

```

### 类型参数 (Type Arguments)

Similar to Rust, Sway has what is colloquially known as the [turbofish](https://github.com/rust-lang/rust/blob/e98309298d927307c5184f4869604bd068d26183/src/test/ui/parser/bastion-of-the-turbofish.rs). The turbofish looks like this: `::<>` (see the little fish with bubbles behind it?). The turbofish is used to annotate types in a generic context. Say you have the following function:

与 Rust 类似，Sway 具有俗称的 \[turbofish]\(<https://github.com/rust-lang/rust/blob/e98309298d927307c5184f4869604bd068d26183/src/test/ui/parser/bastion-of-the-turbofish。> rs).涡轮鱼看起来像这样：`::<>`（看到后面有气泡的小鱼了吗？）。 turbofish 用于在通用上下文中注释类型。假设您具有以下功能：

```
fn foo<T, E>(t: T) -> Result<T, E> {
    Result::Ok(t)
}

```

In this code example, which is admittedly asinine, you can't possibly know what type `E` is. You'd need to provide the type manually, with a turbofish:

在这个公认是愚蠢的代码示例中，您不可能知道`E`是什么类型。您需要使用涡轮鱼手动提供类型：

```
fn foo<T, E>(t: T) -> Result<T, E> {
    Result::Ok::<T, MyErrorType>(t)
}

```

It is also common to see the turbofish used on the function itself:

在函数本身上使用 turbofish 也很常见：

```
fn main() {
    foo::<Bar, Baz>()
}

```
