无法创建流畅的API,因为类型`self`与`& mut self`不匹配

时间:2016-08-25 22:03:50

标签: rust

在许多其他语言中,通常使用类似

的API
lng

在Rust中遇到问题,如果obj.do_x() .do_y() do_xdo_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

2 个答案:

答案 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