1 个稳定版本
1.0.0 | 2024年3月17日 |
---|
#4 in #tryfrom
在 derive_constructors 中使用
42KB
503 代码行
您正在阅读 derive_constructors 版本 1.0.0 的文档
允许通过提供如字段名称等简单信息来派生多个构造函数,并为结构体实现 [From] 和 [TryFrom] 特性。
还允许为枚举派生 [From]。
1 结构体的 Derive 宏:From 和 TryFrom
参考:derive_constructors_proc::From, derive_constructors_proc::TryFrom
这些允许您在需要将字段元组传递给 From::from 或 TryFrom::try_from 函数的地方派生 [From] 和 [TryFrom] 特性,例如
#[derive(derive_constructors::From, PartialEq, Debug)]
struct CharacterInfo{
name: String,
age: u8,
#[no_from]
times_appeared: u8,
#[no_from(4)]
years_studied: u8
}
let character_using_from = CharacterInfo::from(("Jorge".to_string(), 23));
let expected_character = CharacterInfo { name: "Jorge".to_string(), age: 23, times_appeared: 0, years_studied: 4};
assert_eq!(character_using_from, expected_character);
2 结构体的属性宏
允许您定义一个构造函数,在 proc 属性中,您可以通过以下属性自定义实现(注意每个属性都是可选的)
-
命名:函数名称,构造函数通常命名为 'with_字段名称',因为调用它们时非常易读,例如
CharacterInfo::with_name_and_age("Jorge", 23)
。
注意:如果没有提供此字段,则不会实现 'with_*' 构造函数,而是实现 [From] 或 [TryFrom] 特性。 -
模式(值:[From, TryFrom],默认:From)
- 当使用 From 模式时,函数接收字段作为参数并返回具有这些值的此结构体,这通常是您所寻找的。
- 当使用TryFrom模式时,函数接收实现了Into、Into...等类型的参数,如果所有字段都能成功转换到您的字段,则返回包含您的结构的[Ok],否则返回包含无法初始化的字段和错误原因的[Err],以下示例说明了这一点。
-
字段(默认值:未包含在'
defaults
'属性中的所有字段):您要为构造函数创建的字段名称,例如:fields(age, name)
可能生成如下函数:fn new(age: u8, name: String) -> CharacterInfo
。 -
默认值:说明如何初始化《code>fields属性中未涵盖的字段,例如:
defaults(years_studied(4))
。
如果一个字段既不在《code>fields也不在《code>defaults属性中,它将视为通过Default::default初始化,这意味着,未涵盖的《code>times_appeared字段将初始化为0(因为u8::default()是0)。 -
error_enum_named(仅适用于TryFrom模式):指定了当TryFrom函数失败时返回的枚举错误的名称。
-
error_enum_metadata(仅适用于TryFrom模式):声明了当TryFrom函数失败时返回的枚举错误的元数据,您可能需要在其中写入
error_enum_metadata(#[derive(Debug)])
。
2.1 示例1:空构造函数
如果您只应用[constructor]属性,它将仅实现[From]特质,其中它将接收一个由所有字段组成的元组,在这种情况下,from(value: (String, u8)) -> CharacterInfo
。
#[derive(Debug, PartialEq)]
#[derive_constructors::constructor]
struct CharacterInfo{
name: String,
age: u8,
}
let character_using_from = CharacterInfo::from(("Jorge".to_string(), 23));
let expected_character = CharacterInfo { name: "Jorge".to_string(), age: 23 };
assert_eq!(character_using_from, expected_character);
2.2 示例2:使用特定字段的新构造函数
以下示例创建了一个名为new(name: String, age: u8) -> CharacterInfo
的函数。
由于指定了《code>years_studied,它将初始化为4,而《code>times_appeared没有指定,它将初始化为u8::default()(即0)。
#[derive(Debug, PartialEq)]
#[derive_constructors::constructor(named(new), fields(name, age), defaults(years_studied(4)))]
struct CharacterInfo{
name: String,
age: u8,
times_appeared: u8,
years_studied: u8
}
let character_using_from = CharacterInfo::new("Jorge".to_string(), 23);
let expected_character = CharacterInfo { name: "Jorge".to_string(), age: 23, times_appeared: 0, years_studied: 4};
assert_eq!(character_using_from, expected_character);
2.3 示例3:使用TryFrom模式的新构造函数
以下示例创建了一个名为 new(name: T where String: TryFrom<T>, age: U where String: TryFrom<U>) -> Result<CharacterInfo, MyEnumError>
的函数。
由于指定了《code>years_studied,它将初始化为4,而《code>times_appeared没有指定,它将初始化为u8::default()(即0)。
如果出现错误,它将返回一个名为 MyEnumError
的枚举的变体,此枚举被指定为派生 [Debug] 和 [PartialEq]。
let character_using_try_from = CharacterInfo::new("Jorge", 23_u16).unwrap();
let expected_character = CharacterInfo { name: "Jorge".to_string(), age: 23, times_appeared: 0, years_studied: 4};
assert_eq!(character_using_try_from, expected_character);
let produced_error = u8::try_from(23000_u16).unwrap_err();
let forced_error_using_try_from = CharacterInfo::new("Jorge", 23000_u16).unwrap_err();
let expected_error_on_try_from = MyEnumError::AgeError(produced_error);
assert_eq!(forced_error_using_try_from, expected_error_on_try_from);
#[derive(Debug, PartialEq)]
#[derive_constructors::constructor(
named(new),
fields(name, age),
defaults(years_studied(4)),
pattern(TryFrom),
error_enum_named(MyEnumError),
error_enum_metadata(#[derive(Debug, PartialEq)])
)]
struct CharacterInfo{
name: String,
age: u8,
times_appeared: u8,
years_studied: u8,
}
3 枚举的 Derive 宏:From
此实现为每个枚举实现了 From 特性,通过在每个枚举上创建一个 From::from 函数,并将每个字段作为值,例如
#[derive(derive_constructors::From, Debug, PartialEq)]
enum MyValue{
StaticString(&'static str),
Number(i32),
Boolean(bool),
}
let scattered_values = vec![MyValue::from("Age "), MyValue::from(23), MyValue::from(", over age "), MyValue::from(true)];
let specified = vec![MyValue::StaticString("Age "), MyValue::Number(23), MyValue::StaticString(", over age "), MyValue::Boolean(true)];
assert_eq!(scattered_values, specified);
依赖项
~2MB
~43K SLoC