Hello, does anyway know a pretty way to do the following?
let len = a.len().min(b.len());
let dst = b.get_mut(..len).unwrap();
let src = a.get(..len).unwrap();
use(dst, srt);
Hello, does anyway know a pretty way to do the following?
let len = a.len().min(b.len());
let dst = b.get_mut(..len).unwrap();
let src = a.get(..len).unwrap();
use(dst, srt);
Maybe you prefer indexing? It does the panicking implicitly:
fn main() {
let a: String = String::new();
let mut b: Vec<u8> = vec![];
let len = a.len().min(b.len());
let dst = &mut b[..len];
let src = &a[..len].as_bytes();
r#use(dst, src);
}
fn r#use(_: &mut [u8], _: &[u8]) {}
It still contains panic paths, while I would like to not have them at all
Note that the optimizer is able to remove both panic paths Compiler Explorer
In cases where the compiler can't optimize these, you can use unchecked
methods.
Yes, but this is not guaranteed by type system and generally is not pretty.
It is like using
if option.is_some() {
let value = option.unwrap();
...
}
instead of
if let Some(value) = option {
...
}
Assuming you can change the argument type of use
: have it take an iterator over pairs:
use(b.iter().zip(a.iter()))
Having things guaranteed by the type system is nice, but for many advanced patterns it's not really feasible outside of languages with dependent types (where your code is effectively a mathematical proof that it's correct)
Rust's type system can't reason about run-time sized types like slices. It might be possible for arrays, but const generics aren't powerful enough for this yet on stable.
For unwraps that you know can't fail, you could use .unwrap_or_default()
that usually generates easier to optimize code, leaves less code bloat in cases where it can't be optimized out.
Define a helper function and use that. The code using the function won't need unwrap
or indexing:
/// This function never panics.
fn equal_length_prefixes<'a, 'b, T>(a: &'a [T], b: &'b [T]) -> (&'a [T], &'b [T]) {
let len = a.len().min(b.len());
(&a[..len], &b[..len])
}
This is probably too clever, but there's no panic path:
let src = match a.get(..b.len()) {
Some(src) => src,
None => &a,
};
let dst = match b.get_mut(..a.len()) {
Some(dst) => dst,
None => &mut b,
};
EDIT: The compiler error below is fixed with the next version of the borrow checker, polonius, so it isn't directly related to this topic.
I like it! Although I wasn't able to use this to write a function that returns the slices this way:
fn prefixes<'a, 'b, T>(a: &'a [T], b: &'b mut [T]) -> (&'a [T], &'b mut [T]) {
let src = match a.get(..b.len()) {
Some(src) => src,
None => a,
};
let dst = match b.get_mut(..a.len()) {
Some(dst) => dst,
None => b,
};
(src, dst)
}
error[E0499]: cannot borrow `*b` as mutable more than once at a time
--> src/lib.rs:17:25
|
10 | fn prefixes<'a, 'b, T>(a: &'a [T], b: &'b mut [T]) -> (&'a [T], &'b mut [T]) {
| -- lifetime `'b` defined here
...
15 | let dst = match b.get_mut(..a.len()) {
| - first mutable borrow occurs here
16 | Some(dst) => dst,
17 | None => b,
| ^ second mutable borrow occurs here
18 | };
19 | (src, dst)
| ---------- returning this value requires that `*b` is borrowed for `'b`
However, slicing does work:
fn prefixes<'a, 'b, T>(a: &'a [T], b: &'b mut [T]) -> (&'a [T], &'b mut [T]) {
let len = a.len().min(b.len());
(&a[..len], &mut b[..len])
}
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.