给定的是带有 u32
字段的结构。它完全具有一种超载方法,可以用作该字段的设置器和Getter。
pub struct Struct {
value: u32
}
pub trait Trait<T> {
fn method(&mut self, arg: T);
}
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&mut self, arg: &mut u32) {
*arg = self.value;
}
}
该结构的可能用途可能是以下
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
s.method(&mut v);
println!("The value of s is: {}", v);
s.method(3);
s.method(&mut v);
println!("The value of s is: {}", v);
}
优点,即调用过载的方法,而不是直接访问字段时,当结构在FFI接口中使用时,有两个原因。一方面,该方法仍然可以对值进行修改,例如首先将&amp; str
转换为 cstring
,然后存储*const u8
作为值,它使得字符串可用于C。另一方面,该方法还可以使用C中使用它的名称,而不是编写 setValue
和<代码> getValue ,例如。但是,正如您在这里看到的那样,这两种方法之一不需要对自我的可变引用,因为它不会改变价值字段,而是因为特征需要它,因此无论如何在两种情况下都使用。该结构不仅在FFI方法中配置,然后用作参数,而且还可以作为该方法的返回值出现,在这种情况下,它将作为不可变的参考返回,只能从中读取。自定义的性状实现看起来很
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&self, arg: &mut u32) {
*arg = self.value;
}
}
明显,因为第二个Inpl Block没有与性状相同的方法签名。我已经尝试使用 notunary_self_types
功能将自我参数定义为性状中的另一个通用参数,但不幸的是这不起作用。
Given is a struct with a u32
field. It has exactly one overloaded method that can be used as both setter and getter for the field.
pub struct Struct {
value: u32
}
pub trait Trait<T> {
fn method(&mut self, arg: T);
}
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&mut self, arg: &mut u32) {
*arg = self.value;
}
}
A possible use of this structure could be as follows
fn main() {
let mut s = Struct { value: 0 };
let mut v = 0;
s.method(&mut v);
println!("The value of s is: {}", v);
s.method(3);
s.method(&mut v);
println!("The value of s is: {}", v);
}
The advantage of calling an overloaded method instead of accessing the field directly serves two reasons when the struct is used in a ffi interface. On the one hand, the method can still make modifications to the value, such as first converting a &str
to a CString
and then storing the *const u8
as the value, which makes the string usable for C. On the other hand, overloading the method also makes it possible to use the names given for it in C instead of writing setValue
and getValue
, for example. However, as you can see here, one of the two methods does not need a mutable reference to self because it does not change the value field, but because the trait requires it, it is used in both cases anyway. The struct is not only configured and then used as argument in a ffi method, but can also occur as return value of such a method, in which case it will be returned as a immutable reference and should only be read from. The customized trait implementations would look like this
impl Trait<u32> for Struct {
fn method(&mut self, arg: u32) {
self.value = arg;
}
}
impl Trait<&mut u32> for Struct {
fn method(&self, arg: &mut u32) {
*arg = self.value;
}
}
Obviously this won't work here because the second impl block doesn't have the same method signature as the trait. I already tried to define the self paramter as another generic parameter in the trait using the arbitrary_self_types
features but unfortunately that didn't work.
发布评论
评论(1)
您无法在突变性方面进行参数化。
请参阅:
您可以在
self
上参数化,但它将不再是一种方法,只有一个关联的功能:给定RFC 精制的特征实现,这使得可能对精炼 在其实现中的一个特征,即编写一个较少通用的IMP(例如,特征中不安全的安全方法),您也可能能够在将来可以完善可变性(尽管我尚无“看到有关此的讨论),但这只会在您使用具体实例而不是仿制药时放松限制。
一种或另一种方式,我认为这种设计是不正确的。只需使用普通
value()
和set_value()
方法,这很简单且显而易见。You cannot parameterize over mutability.
See:
You can parameterize on
self
, but it will not be a method anymore, only an associated function:Given the draft RFC Refined trait implementations that poses the possibility to refine a trait in its implementation, i.e. to write a less generic impl (e.g. safe method in the impl that is unsafe in the trait), it may be possible that you will be able to refine mutability in the future too (although I haven't seen discussions about that), but that will only relax the restriction when you work with a concrete instance, not with generics.
One way or the other, I don't think this design is correct. Just use normal
value()
andset_value()
methods, it is simple and obvious.