2017-08-05 57 views
1

如何正確使用預計在循環中使用method chaining的構建器模式?使用來自log4rs的示例。注意self不是appender中的參考。如何在循環中使用鏈式生成器模式而不會產生編譯器錯誤?

//builder pattern from log4rs 

pub struct ConfigBuilder { 
    appenders: Vec<Appender>, 
    loggers: Vec<Logger>, 
} 

impl ConfigBuilder { 
    pub fn appender(mut self, appender: Appender) -> ConfigBuilder { 
     self.appenders.push(appender); 
     self 
    } 
} 

做一個錯誤下面這樣的結果,因爲(我認爲)cb是越來越移動到.appender()返回的內存。

let cb = ConfigBuilder::new(); 
for x in ys { 
    cb.appender(x); 
} 

下面這似乎工作。這是唯一的方法嗎?

let mut cb = ConfigBuilder::new(); 
for x in ys { 
    cb = cb.appender(x); 
} 
+0

你已經讓'appender'獲得了所有權並返回新的構建器,所以你需要將返回值放在某個地方。你故意選擇這種設計嗎?如果你想讓第一個例子的循環工作,你需要傳遞一個可變的自引用。 – loganfsmyth

+0

@loganfsmyth - 對不起,如果我不清楚,那個例子來自log4rs包。 https://crates.io/crates/log4rs。不是我的設計。 – marathon

+0

另請參閱https://stackoverflow.com/q/34362094/155423 – Shepmaster

回答

4

這是做到這一點的唯一途徑?

從語義上講,它是關鍵的方法,儘管還有其他寫法。 appender功能需要mut self,因此它將取得cb變量值的所有權,並使該變量在該點之後不可用。它本可以設計借用一個參考,但鏈接很好。由於您處於循環中,因此構建器需要在下一次迭代中可用,因此您需要將值分配給新的東西。這意味着,

let mut cb = ConfigBuilder::new(); 
for x in ys { 
    cb = cb.appender(x); 
} 

的確是一種方法來做到這一點。另一種方法是使用Iterator's .fold

let cb = ys.into_iter() 
    .fold(ConfigBuilder::new(), |cb, x| cb.appender(x)); 

其保持在一個分配的一切,但在其他方面幾乎相同。