When I try to implement a simple Rust sample of Command Pattern following the book Head First Design Patterns, the issues of lifetime really drive me crazy. I think I still cannot fully understand the lifetime in Rust. Can someone be so kind as to point out where I did wrong or give me a better implementation? Thanks.
The Java codes in Head First Design Patterns are simple as below:
public interface Command {
void execute();
}
public class RemoteControl {
private Command[] onCommands= new Command[7];
private Command[] offCommands = new Command[7];
public void setCommand(int slot, Command onCommand,Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonPressed(int slot) {
onCommands[slot].execute();
}
public void offButtonPressed(int slot) {
offCommands[slot].execute();
}
}
public class Light {
private boolean on;
private int order;
public Light(boolean on, int order) {
this.on = on;
this.order = order;
}
public void switchLight() {
if (on)
System.out.printf("Light %d turned off\n", order);
else
System.out.printf("Light %d turned on\n", order);
on = !on;
}
}
public class LightSwitchCommand implements Command {
private Light light;
public LightSwitchCommand(Light light) {
this.light = light;
}
public void execute() {
light.switchLight();
}
}
public static void main(String[] args) {
Light l1 = new Light(true,1);
Light l2 = new Light(true,2);
LightSwitchCommand l1switch = new LightSwitchCommand(l1);
LightSwitchCommand l2switch = new LightSwitchCommand(l2);
RemoteControl remote = new RemoteControl();
remote.setCommand(0,l1switch,null);
remote.setCommand(1,l2switch,null);
remote.onButtonPressed(0);
remote.onButtonPressed(1);
}
However, when trying to transfer them into Rust, I am frastrated by issues of lifetime.
My codes are below:
pub struct RemoteControl<'a>{
on_commands: [Option<Box<dyn MutCommand + 'a>>; 7],
off_commands: [Option<Box<dyn MutCommand + 'a>>; 7]
}
impl<'a> RemoteControl<'a>{
pub fn new() -> RemoteControl{ // here comes the lifetime issue
RemoteControl {
on_commands:[None;7],
off_commands:[None,7]
}
}
pub fn set_command(&mut self, slot: i32, on_command: Option<Box<dyn MutCommand + 'a>>, off_command: Option<Box<dyn MutCommand + 'a>>){
self.on_commands[slot] = on_command;
self.off_commands[slot] = off_command;
}
pub fn on_button_pressed(&mut self, slot: i32){
match self.on_commands[slot] {
None => {},
Some(cmd) => cmd.mut_execute()
};
}
pub fn off_button_pressed(&mut self, slot: i32){
match self.on_commands[slot] {
None => {},
Some(cmd) => cmd.mut_execute()
};
}
}
pub trait MutCommand{
fn mut_execute(&mut self);
}
pub struct SwitchLightCommand<'a>{
light: &'a mut Light
}
impl<'a> SwitchLightCommand<'a>{
pub fn new(light: &'a mut Light) -> SwitchLightCommand{
SwitchLightCommand { light }
}
}
impl<'a> MutCommand for SwitchLightCommand<'a>{
fn mut_execute(&mut self){
self.light.switch();
}
}
pub struct Light{
on: bool,
order: u8
}
impl Light{
pub fn new(light_on: bool, order: u8) -> Light{
Light { on: light_on, order }
}
pub fn switch(&mut self){
if self.on{
println!("Light {} turned off", self.order);
} else {
println!("Light {} turned on", self.order);
}
self.on = !self.on;
}
}
The error massge given by the compiler is below. I really don't know how to deal with it. The given help seems not to work.
error[E0106]: missing lifetime specifier
--> src\command_pattern.rs:16:21
|
16 | pub fn new() -> RemoteControl
| ^^^^^^^^^^^^^ help: consider giving it a 'static lifetime: `RemoteControl + 'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
And it seems that the section talking about lifetime in The book is not very helpful for this situation.