Cannot borrow as immutable because it is also borrowed as mutable when verifing that a closure was called
I have a function that takes a closure to perform output-related logic (e.g. display to stdout):
fn handle(mut output: impl FnMut(String) -> ()) -> Result<(), String> {
// do something that produces output string `message`
let message = "example".to_string();
Ok(output(message))
}
I'm trying to write an integration test for this function, where I define a stub output function, which saves the output string to local mutable variable:
#[test]
fn should_work() {
let mut output_message = String::from("");
let output = |message: String| {
output_message = message;
};
let result = handle(output);
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
However I have error:
error[E0502]: cannot borrow `output_message` as immutable because it is also borrowed as mutable
--> src/lib.rs:18:24
|
11 | let output = |message: String| {
| ----------------- mutable borrow occurs here
12 | output_message = message;
| -------------- previous borrow occurs due to use of `output_message` in closure
...
18 | assert_eq!("blah", output_message);
| ^^^^^^^^^^^^^^ immutable borrow occurs here
19 | }
| - mutable borrow ends here
Is there any way I can test using this approach? I briefly searched for some mock crates but all of the crates don't seem to be updated very often and they are a bit overkill for my scenario anyway.
If not, any better alternative to test this function?
testing rust integration-testing
add a comment |
I have a function that takes a closure to perform output-related logic (e.g. display to stdout):
fn handle(mut output: impl FnMut(String) -> ()) -> Result<(), String> {
// do something that produces output string `message`
let message = "example".to_string();
Ok(output(message))
}
I'm trying to write an integration test for this function, where I define a stub output function, which saves the output string to local mutable variable:
#[test]
fn should_work() {
let mut output_message = String::from("");
let output = |message: String| {
output_message = message;
};
let result = handle(output);
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
However I have error:
error[E0502]: cannot borrow `output_message` as immutable because it is also borrowed as mutable
--> src/lib.rs:18:24
|
11 | let output = |message: String| {
| ----------------- mutable borrow occurs here
12 | output_message = message;
| -------------- previous borrow occurs due to use of `output_message` in closure
...
18 | assert_eq!("blah", output_message);
| ^^^^^^^^^^^^^^ immutable borrow occurs here
19 | }
| - mutable borrow ends here
Is there any way I can test using this approach? I briefly searched for some mock crates but all of the crates don't seem to be updated very often and they are a bit overkill for my scenario anyway.
If not, any better alternative to test this function?
testing rust integration-testing
2
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22
add a comment |
I have a function that takes a closure to perform output-related logic (e.g. display to stdout):
fn handle(mut output: impl FnMut(String) -> ()) -> Result<(), String> {
// do something that produces output string `message`
let message = "example".to_string();
Ok(output(message))
}
I'm trying to write an integration test for this function, where I define a stub output function, which saves the output string to local mutable variable:
#[test]
fn should_work() {
let mut output_message = String::from("");
let output = |message: String| {
output_message = message;
};
let result = handle(output);
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
However I have error:
error[E0502]: cannot borrow `output_message` as immutable because it is also borrowed as mutable
--> src/lib.rs:18:24
|
11 | let output = |message: String| {
| ----------------- mutable borrow occurs here
12 | output_message = message;
| -------------- previous borrow occurs due to use of `output_message` in closure
...
18 | assert_eq!("blah", output_message);
| ^^^^^^^^^^^^^^ immutable borrow occurs here
19 | }
| - mutable borrow ends here
Is there any way I can test using this approach? I briefly searched for some mock crates but all of the crates don't seem to be updated very often and they are a bit overkill for my scenario anyway.
If not, any better alternative to test this function?
testing rust integration-testing
I have a function that takes a closure to perform output-related logic (e.g. display to stdout):
fn handle(mut output: impl FnMut(String) -> ()) -> Result<(), String> {
// do something that produces output string `message`
let message = "example".to_string();
Ok(output(message))
}
I'm trying to write an integration test for this function, where I define a stub output function, which saves the output string to local mutable variable:
#[test]
fn should_work() {
let mut output_message = String::from("");
let output = |message: String| {
output_message = message;
};
let result = handle(output);
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
However I have error:
error[E0502]: cannot borrow `output_message` as immutable because it is also borrowed as mutable
--> src/lib.rs:18:24
|
11 | let output = |message: String| {
| ----------------- mutable borrow occurs here
12 | output_message = message;
| -------------- previous borrow occurs due to use of `output_message` in closure
...
18 | assert_eq!("blah", output_message);
| ^^^^^^^^^^^^^^ immutable borrow occurs here
19 | }
| - mutable borrow ends here
Is there any way I can test using this approach? I briefly searched for some mock crates but all of the crates don't seem to be updated very often and they are a bit overkill for my scenario anyway.
If not, any better alternative to test this function?
testing rust integration-testing
testing rust integration-testing
edited Nov 15 '18 at 15:43
Shepmaster
154k14306446
154k14306446
asked Nov 14 '18 at 16:10
Phuong NguyenPhuong Nguyen
2,2251717
2,2251717
2
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22
add a comment |
2
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22
2
2
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22
add a comment |
2 Answers
2
active
oldest
votes
You can put the anonymous function in a local scope, so that it is dropped by the time you assert:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = {
let output = |message: String| {
output_message = message;
};
handle(output)
};
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
add a comment |
Inline the closure:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = handle(|message| {
output_message = message;
});
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
This way, the closure is a temporary and doesn't borrow the value for a long time. As a bonus, you can avoid the type specification on the closure argument.
Or wait a few weeks until Rust 1.31 and turn on Rust 2018 mode, which has non-lexical lifetimes.
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53304433%2fcannot-borrow-as-immutable-because-it-is-also-borrowed-as-mutable-when-verifing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can put the anonymous function in a local scope, so that it is dropped by the time you assert:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = {
let output = |message: String| {
output_message = message;
};
handle(output)
};
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
add a comment |
You can put the anonymous function in a local scope, so that it is dropped by the time you assert:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = {
let output = |message: String| {
output_message = message;
};
handle(output)
};
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
add a comment |
You can put the anonymous function in a local scope, so that it is dropped by the time you assert:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = {
let output = |message: String| {
output_message = message;
};
handle(output)
};
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
You can put the anonymous function in a local scope, so that it is dropped by the time you assert:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = {
let output = |message: String| {
output_message = message;
};
handle(output)
};
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
answered Nov 14 '18 at 16:17
TarmilTarmil
8,4132232
8,4132232
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
add a comment |
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
thanks a lot, works like a charm
– Phuong Nguyen
Nov 14 '18 at 23:24
add a comment |
Inline the closure:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = handle(|message| {
output_message = message;
});
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
This way, the closure is a temporary and doesn't borrow the value for a long time. As a bonus, you can avoid the type specification on the closure argument.
Or wait a few weeks until Rust 1.31 and turn on Rust 2018 mode, which has non-lexical lifetimes.
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
add a comment |
Inline the closure:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = handle(|message| {
output_message = message;
});
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
This way, the closure is a temporary and doesn't borrow the value for a long time. As a bonus, you can avoid the type specification on the closure argument.
Or wait a few weeks until Rust 1.31 and turn on Rust 2018 mode, which has non-lexical lifetimes.
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
add a comment |
Inline the closure:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = handle(|message| {
output_message = message;
});
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
This way, the closure is a temporary and doesn't borrow the value for a long time. As a bonus, you can avoid the type specification on the closure argument.
Or wait a few weeks until Rust 1.31 and turn on Rust 2018 mode, which has non-lexical lifetimes.
Inline the closure:
#[test]
fn should_work() {
let mut output_message = String::from("");
let result = handle(|message| {
output_message = message;
});
assert!(result.is_ok());
assert_eq!("blah", output_message);
}
This way, the closure is a temporary and doesn't borrow the value for a long time. As a bonus, you can avoid the type specification on the closure argument.
Or wait a few weeks until Rust 1.31 and turn on Rust 2018 mode, which has non-lexical lifetimes.
answered Nov 15 '18 at 15:42
ShepmasterShepmaster
154k14306446
154k14306446
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
add a comment |
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
thanks a lot. Coincidentally I also just saw your answer on sharing test utilities: stackoverflow.com/a/44545091/1273147
– Phuong Nguyen
Nov 16 '18 at 1:10
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53304433%2fcannot-borrow-as-immutable-because-it-is-also-borrowed-as-mutable-when-verifing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
For what it's worth, your code works without any changes when enabling non-lexical lifetimes.
– Sven Marnach
Nov 14 '18 at 19:16
@SvenMarnach interesting, I don't know about that
– Phuong Nguyen
Nov 14 '18 at 23:22