Reputation: 185
I'm in the process of learning Rust. I find "over-engineering"toy examples to be a useful thing to do in the early stages, which has led me to this situation.
Starting with this simple function:
extern crate data_encoding;
use std::ops::BitXor;
use data_encoding::hex;
use std::iter::FromIterator;
fn fixed_xor_basic(l: &[u8], r: &[u8]) -> Vec<u8> {
l.iter().zip(r.iter()).map(|(x, y)| *x ^ *y).collect()
}
#[test]
fn test_fixed_xor_basic() {
let input_1 = hex::decode(b"1C0111001F010100061A024B53535009181C").unwrap();
let input_2 = hex::decode(b"686974207468652062756C6C277320657965").unwrap();
let expected_output = hex::decode(b"746865206B696420646F6E277420706C6179").unwrap();
assert_eq!(fixed_xor_basic(&input_1, &input_2), expected_output);
}
I moved onto a simple variant getting rid of the allocation:
fn fixed_xor_basic_inplace(l: &mut [u8], r: &[u8]) {
for (left, right) in l.iter_mut().zip(r.iter()) {
*left = *left ^ *right;
}
}
And another which accepts any type which can be XORed:
fn fixed_xor_generic<T>(l: &[T], r: &[T]) -> Vec<T>
where T: BitXor + Copy,
Vec<T>: FromIterator<<T as BitXor>::Output> {
l.iter().zip(r.iter()).map(|(x, y)| *x ^ *y).collect()
}
This second variant initially didn't compile -- but the error message hinted me towards adding the constraint Vec<T>: FromIterator<<T as BitXor>::Output>
. Presumably this constraint has given the compiler some hint that BitXor::Output
is in fact the same thing as T
, but I'm not clear on what exactly that hint is.
Now... combining the two has me stumped:
fn fixed_xor_generic_inplace<T>(l: &mut [T], r: &[T])
where T: BitXor + Copy {
for (left, right) in l.iter_mut().zip(r.iter()) {
*left = *left ^ *right;
}
}
Produces an error:
error[E0308]: mismatched types
--> src/xor_lib.rs:27:17
|
27 | *left = *left ^ *right;
| ^^^^^^^^^^^^^^ expected type parameter, found associated type
|
= note: expected type `T`
= note: found type `<T as std::ops::BitXor>::Output`
error: aborting due to previous error
I strongly suspect that the two situations are similar and that I need to provide some extra bit of context to help the compiler figure out the T
is in fact <T as std::ops::BitXor>::Output
by another name.
Am I on the right track? If so, what would this hint be?
(also the next challenge is making the function accept IntoIterator types rather than slices -- if that might affect the solution at all).
Upvotes: 3
Views: 134
Reputation: 58815
You just need to tell the compiler that the associated type Output
is the same as T
.
fn fixed_xor_generic_inplace<T>(l: &mut [T], r: &[T])
where T: BitXor<Output = T> + Copy {
for (left, right) in l.iter_mut().zip(r.iter()) {
*left = *left ^ *right;
}
}
Upvotes: 2