# 复合类型

行百里者半五十，欢迎大家来到这里，虽然还不到中点，但是已经不远了。如果说之前学的基础数据类型是原子，那么本章将讲的数据类型可以认为是分子。

本章的重点在复合类型上，顾名思义，复合类型是由其它类型组合而来，最典型的就是结构体`struct`和枚举`enum`。例如一个2D的点`point(x,y)`，它从两个数值类型组合而来。我们不想单独去维护这两个数值，而是希望把它们看作一个整体去认识和处理。

来看一段代码，它使用我们之前学过的内容来构建文件操作：
```rust
#![allow(unused_variables)]
type File = String;

fn open(f: &mut File) -> bool {
    true
}
fn close(f: &mut File) -> bool {
    true
}

#[allow(dead_code)]
fn read(f: &mut File, save_to: &mut Vec<u8>) -> ! {
    unimplemented!()
}

fn main() {
    let mut f1 = File::from("f1.txt");
    open(&mut f1);
    //read(&mut f1, &mut vec![]);
    close(&mut f1);
}
 ```

 当前阶段非常类似原型设计：提供api接口，但是不去实现它们。因此在这个阶段我们需要排除一些编译器噪音，引入了`#![allow(unused_variables)]`属性标记，该标记会告诉编译器无视未使用的变量，不要抛出`warning`警告,具体的常见编译器属性你可以在这里查阅：[编译器属性标记](../../compiler/attributes.md).

 `read`函数也非常有趣，它返回一个`!`，这个表明该函数是一个发散函数，不会返回任何值，包括`()`。`unimplemented!()`告诉编译器该函数尚未实现，其实主要帮助我们快速完成主要代码，回头可以通过搜索这些标记来完成次要代码，类似的还有`todo!()`，当代码执行到这种未实现的地方时，程序会直接报错: 你可以反注释`read(&mut f1, &mut vec![]);`这行，然后再观察下结果。

 同时，从代码设计角度来看，假如关于文件操作的类型和函数散落的到处都是，是难以管理和使用的。而且`open(&mut f1)`也远没有`f1.open()`好，因此这就是基本类型的局限性：**无法从更高的抽象层次去简化代码**。


接下来，我们将引入一个高级数据结构 - 结构体`struct`，来看看怎么样更好的解决这类问题。 开始之前，先来看看何为`元组`.