问题描述
在许多语言中,一个常见的构造函数习惯用法是使用如下伪代码的语法来初始化对象的值:
In many languages, a common constructor idiom is to initialize values of an object using syntax like this pseudocode:
constructor Foo(args...) {
for arg {
object.arg = arg
}
}
Rust 起初似乎也不例外.struct
的许多 impl
包含一个名为 new
的构造函数,用于将一系列有序的参数压缩到结构体的字段上:
Rust at first seems to be no exception. Many impl
for a struct
include a constructor named new
to zip an ordered series of arguments onto the fields of the struct:
struct Circle {
x: i32,
y: i32,
radius: i32,
}
impl Circle {
fn new(x: i32, y: i32, radius: i32) -> Circle {
Circle { x: x, y: y, radius: radius }
}
}
使用宏执行此操作可能类似于 zip!(Circle, 52, 32, 5)
.它会将值按顺序压缩到 Circle
的字段上.zip!(Circle, 52, 32)
或 zip!(Circle, 52, 32, 5, 100)
都会出现问题,但像这样的宏将是无需太多样板即可将值推送到任何结构的新实例的非常灵活的方法.
Doing this with a macro might look like zip!(Circle, 52, 32, 5)
. It would zip the values, in order, onto the fields of Circle
. Both zip!(Circle, 52, 32)
or zip!(Circle, 52, 32, 5, 100)
would present issues, but a macro like this would be a very flexible way to push values onto a new instance of any struct without so much boilerplate.
有没有一种惯用的方法来简化这个样板文件?如何在不显式编写样板代码的情况下将一系列有序参数映射到结构的每个字段上?
Is there an idiomatic way to simplify this boilerplate? How is it possible to map a series of ordered arguments onto each field of a struct without explicitly writing the boilerplate code to do so?
推荐答案
这对宏来说是不可能的,原因很简单:宏不能凭空想象字段名称.
This is not possible with a macro for a very simple reason: a macro cannot conjure the field names out of thin air.
如果您愿意公开类型的详细信息,最简单的解决方案是公开字段:
The simplest solution, if you are comfortable exposing the details of your type, is making the fields public:
struct Circle {
pub x: i32,
pub y: i32,
pub radius: i32,
}
fn main() {
let circle = Circle { x: 3, y: 4, radius: 5 };
}
也就是说,没有需要有一个构造函数,没有它也能正常工作.
That is, there is no need to have a constructor, it works perfectly fine without one.
毕竟,如果构造函数除了传递值之外什么都不做,那么构造函数本身就毫无意义,不是吗?
After all, if the constructor does nothing else than passing on the values, the constructor itself is rather pointless, isn't it?
如果您希望提供更短的初始化语法,您可以例如:
If you wish to offer a shorter initialization syntax, you can for example:
use std::convert::From;
impl From<(i32, i32, i32)> for Circle {
fn from(t: (i32, i32, i32)) -> Circle {
Circle { x: t.0, y: t.1, radius: t.2 }
}
}
fn main() {
let circle: Circle = (3, 4, 5).into();
}
通常,类型推断应该让您不必拼写: Circle
.
然而,我会注意到这更容易出错,因为在没有注意到的情况下交换两个参数要容易得多.您可能希望坚持使用显式名称,或者引入显式类型.
I would note however that this is much more error-prone, as swapping two of the arguments without noticing is much easier. You may want to stick to explicit names, or instead introduce explicit types.
这篇关于如何使用一系列参数初始化结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!