结构体、元组和枚举
结构体
Sway 中的结构是类型的命名分组。您可能还通过另一个名称来熟悉结构:产品类型。 Sway 没有对结构进行任何明显独特的用法;它们与大多数具有结构的其他语言类似。如果您有面向对象的背景,那么结构就像对象的数据属性。
首先,我们声明一个名为Foo
的结构体,它有两个字段。第一个字段名为bar
,它接受类型为u64
的值,第二个字段名为baz
,它接受类型为bool
的值。
library;
// Declare a struct type
pub struct Foo {
bar: u64,
baz: bool,
}
// Struct types for destructuring
pub struct Point {
x: u64,
y: u64,
}
pub struct Line {
p1: Point,
p2: Point,
}
pub struct TupleInStruct {
nested_tuple: (u64, (u32, (bool, str))),
}
为了实例化结构,我们使用结构实例化语法,它与声明语法非常相似,只是用表达式代替类型。
实例化结构体的方法有3种。
- 字段的硬编码值
- 传入名称与结构字段不同的变量
- 通过与字段名称相同的变量使用简写符号
library;
mod data_structures;
use data_structures::{Foo, Line, Point, TupleInStruct};
fn hardcoded_instantiation() -> Foo {
// Instantiate `foo` as `Foo`
let mut foo = Foo {
bar: 42,
baz: false,
};
// Access and write to "baz"
foo.baz = true;
// Return the struct
foo
}
fn variable_instantiation() -> Foo {
// Declare variables with the same names as the fields in `Foo`
let number = 42;
let truthness = false;
// Instantiate `foo` as `Foo`
let mut foo = Foo {
bar: number,
baz: truthness,
};
// Access and write to "baz"
foo.baz = true;
// Return the struct
foo
}
fn shorthand_instantiation() -> Foo {
// Declare variables with the same names as the fields in `Foo`
let bar = 42;
let baz = false;
// Instantiate `foo` as `Foo`
let mut foo = Foo { bar, baz };
// Access and write to "baz"
foo.baz = true;
// Return the struct
foo
}
fn struct_destructuring() {
let point1 = Point { x: 0, y: 0 };
// Destructure the values from the struct into variables
let Point { x, y } = point1;
let point2 = Point { x: 1, y: 1 };
// If you do not care about specific struct fields then use ".." at the end of your variable list
let Point { x, .. } = point2;
let line = Line {
p1: point1,
p2: point2,
};
// Destructure the values from the nested structs into variables
let Line {
p1: Point { x: x0, y: y0 },
p2: Point { x: x1, y: y1 },
} = line;
// You may also destructure tuples nested in structs and structs nested in tuples
let tuple_in_struct = TupleInStruct {
nested_tuple: (42u64, (42u32, (true, "ok"))),
};
let TupleInStruct {
nested_tuple: (a, (b, (c, d))),
} = tuple_in_struct;
let struct_in_tuple = (Point { x: 2, y: 4 }, Point { x: 3, y: 6 });
let (Point { x: x0, y: y0 }, Point { x: x1, y: y1 }) = struct_in_tuple;
}
注释 您可以混合和匹配所有3种方法来同时实例化结构。 此外,字段的顺序在实例化时并不重要,但是我们鼓励按字母顺序声明字段并以相同的字母顺序实例化它们
此外,可以使用解构语法从结构中提取多个变量。
结构内存布局
注释 如果您是语言新手,或者是编程新手,那么这些信息并不重要
结构体的内存开销为零。这意味着在内存中,每个结构字段都是按顺序排列的。运行时不保留有关结构体名称或其他属性的元数据。换句话说,结构体是编译时构造。这在Rust中是相同的,但在其他具有运行时的语言(如Java)中则不同。
元组
元组是一种基本的静态长度类型 其内部包含多种不同的类型。元组的类型由其中值的类型定义,元组可以包含基本类型以及结构体和枚举。
您可以使用.
语法直接访问值。此外,可以使用解构语法从元组中提取多个变量。
library;
fn tuple() {
// You can declare the types youself
let tuple1: (u8, bool, u64) = (100, false, 10000);
// Or have the types be inferred
let mut tuple2 = (5, true, ("Sway", 8));
// Retrieve values from tuples
let number = tuple1.0;
let sway = tuple2.2.1;
// Destructure the values from the tuple into variables
let (n1, truthness, n2) = tuple1;
// If you do not care about specific values then use "_"
let (_, truthness, _) = tuple2;
// Internally mutate the tuple
tuple2.1 = false;
// Or change the values all at once (must keep the same data types)
tuple2 = (9, false, ("Fuel", 99));
}
枚举
枚举也称为求和类型。枚举是一种可能是多种变体之一的类型。要声明枚举,您需要枚举所有潜在的变体。
这里,我们定义了五种可能的颜色。每个枚举变体只是颜色名称。由于没有与每个变体关联的额外数据,因此我们说每个变体的类型为()
或单位。
library;
// Declare the enum
enum Color {
Blue: (),
Green: (),
Red: (),
Silver: (),
Grey: (),
}
fn main() {
// To instantiate a variable with the value of an enum the syntax is
let blue = Color::Blue;
let silver = Color::Silver;
}
结构枚举
枚举变量也可以包含额外的数据。看一下这个更实质性的示例,它将结构声明与枚举变体相结合:
library;
struct Item {
price: u64,
amount: u64,
id: u64,
}
enum MyEnum {
Item: Item,
}
fn main() {
let my_enum = MyEnum::Item(Item {
price: 5,
amount: 2,
id: 42,
});
}
枚举的枚举
可以定义枚举的枚举:
library;
pub enum Error {
StateError: StateError,
UserError: UserError,
}
pub enum StateError {
Void: (),
Pending: (),
Completed: (),
}
pub enum UserError {
InsufficientPermissions: (),
Unauthorized: (),
}
首选用途
使用枚举的首选方法是直接使用单个(非嵌套)枚举,因为它们很容易理解并且行很短:
library;
use ::enum_of_enums::{StateError, UserError};
fn preferred() {
let error1 = StateError::Void;
let error2 = UserError::Unauthorized;
}
不适宜
如果您希望通过上面示例中的枚举来使用枚举的嵌套形式Error
,那么您可以使用以下语法将它们实例化为变量:
library;
use ::enum_of_enums::{Error, StateError, UserError};
fn avoid() {
let error1 = Error::StateError(StateError::Void);
let error2 = Error::UserError(UserError::Unauthorized);
}
注意要点:
- 必须导入所需的所有枚举,而不仅仅是
Error
枚举 - 行可能会变得不必要的长(取决于名称)
- 语法不是最符合人体工程学的
枚举内存布局
注释 如果您是语言新手,或者是编程新手,那么这些信息并不重要。
枚举确实有一些内存开销。为了了解所表示的变体,Sway 为枚举变体存储一个单字(8 字节)标签。标记后保留的空间相当于最大枚举变量的大小。因此,要计算内存中枚举的大小,请将 8 个字节添加到最大变体的大小。例如,在上述情况下 Color
,变体均为()
,则大小将为 8 字节,因为最大变体的大小为 0 字节。