How to return an instance that borrows local data

Solution 1:

If you need the AppConfigManager in the calling context, you could instead make it so it is owned by the ExistingProjectInitializer and accessible as a field.

The function would then look like this:

fn prepare_sut_and_stuff() -> (ExistingProjectInitializer, PathBuf, tempfile::TempDir) {
    let base_dir = tempfile::tempdir().unwrap();
    let file_path = base_dir.path().join("config.json");
    let mut file = File::create(&file_path).unwrap();
    write!(file, "{{\"projects\":[]}}").unwrap();

    let config_manager = AppConfigManager::new(file_path).unwrap();

    let sut = ExistingProjectInitializer::new(config_manager);

    (sut, file_path, base_dir)
}

and the caller would obtain the config_manager like this:

let (sut, file_path, base_dir) = prepare_sut_and_stuff();
let config_manager = &sut.config_manager;

This allows you to have clear ownership semantics.

If it is not possible to modify ExistingProjectInitializer to own the config manager, then it can be argued that the prepare_sut_and_stuff() is trying to do two different things:

  1. Initialize a config manager
  2. Initialize a project initializer

Even though having all in one place is certainly convenient, it might be clearer for the initialization of the ExistingProjectInitializer to happen outside of this function.