在许多其他语言中,通常使用类似
的APIlng
在Rust中遇到问题,如果obj.do_x()
.do_y()
,do_x
取do_y
,则类型不匹配。有没有一种优雅的方法来解决这个问题?
例如:
&mut self
问题是,#[derive(Debug)]
struct Counter { count: u32 }
impl Counter {
fn incr(&mut self) -> &mut Counter {
self.count = self.count + 1;
self
}
fn new() -> Counter {
Counter {
count: 0
}
}
}
返回new()
,但是流畅的API需要Counter
。
答案 0 :(得分:8)
为什么要使用参考?
public class MyContext : DbContext
{
public MyContext() : base("dataDb") {}
public DbSet<Owner> Owners { get; set; }
public DbSet<Pet> Pets { get; set; }
}
public class MyInitializer : DropCreateDatabaseAlways<MyContext>
{
protected override void Seed(MyContext context)
{
// seed database here
context.Owners.AddOrUpdate(
new Owner()
{
//name=,
//id=,
Pets = new List<Pet> { new Pet()
{
//id=,
//name=,
},
new Pet()
{
//id=,
//name=,
}}
},
new Owner()
{
//id=,
//name=,
Pets = new List<Pet> { new Pet()
{
//id=,
//name=,,
}
}
}
);
context.SaveChanges();
}
}
public class Owner
{
public int OwnerId { get; set; }
public string Name { get; set; }
public virtual List<Pet> Pets { get; set; }
}
public class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public virtual Owner Owner { get; set; }
}
}
如果您使用原件,则不再存在借用问题:)
注意:虽然适用于构建器模式,但对于常规类型可能会很烦人。
答案 1 :(得分:6)
你是对的,类型不同。你可能会遇到终身问题。我假设你试过这个:
let mut counter = Counter::new().incr().incr();
失败了。然而,将它们分开:
let mut counter = Counter::new();
counter.incr().incr();
..工作正常。编译器实际上会给你一个不错的提示:
help: consider using a `let` binding to increase its lifetime
正如我在评论中所说的那样,在对象实例化过程中“解决”这种流畅的API设计,人们通常会创建一个Builder
类型(“构建器模式”)。例如,你的看起来像这样:
#[derive(Debug)]
struct Counter { count: u32 }
struct CounterBuilder { count: u32 }
impl CounterBuilder {
fn new() -> CounterBuilder {
CounterBuilder {
count: 0
}
}
fn incr(&mut self) -> &mut CounterBuilder {
self.count = self.count + 1;
self
}
fn build(&self) -> Counter {
Counter {
count: self.count
}
}
}
fn main() {
let counter = CounterBuilder::new()
.incr()
.incr()
.build();
println!("Counter value is: {}", counter.count); // Should print 2
assert_eq!(2, counter.count);
}
基本上,这可以通过在build
调用之后放弃借用来解决生命周期问题(它注意到你已经完成了CounterBuilder
的实例)...此时你有构建并准备好的新的具体Counter
对象。
一旦你Counter
实例化了......你可以根据需要通过自己的流畅API修改它......例如:
let mut counter = CounterBuilder::new()
.incr()
.incr()
.build();
counter.local_increment().local_increment(); // For example, if you were to add a "local_increment" fluent method to Counter