This question already has answers here:
What is the difference between "eq()" and "=="?
(2 answers)
Closed 8 months ago.
I'm still new to rust and I'm a bit puzzled by this tiny detail below. From what I understood so far is that == and eq() are pretty much equivalent. I wonder why is dereferencing y required for the operator version but not for the function call. I was expecting that no dereferencing should be required at all since the eq method expects a reference to y anyways.
use std::cmp::{Eq, PartialEq};
struct X{}
struct Y {}
impl PartialEq<Y> for X{
fn eq(&self, rhs: &Y)->bool{
true
}
}
impl PartialEq for X{
fn eq(&self, rhs: &X)->bool{
true
}
}
impl Eq for X {}
fn main() {
let x = X{};
let y = Y{};
let f1 = |y: &Y| x == *y;
let f2 = |y: &Y| x.eq(y);
}
Playground
Because eq() and == are not equivalent.
Even without autoref, when you call a == b, Rust does not execute PartialEq::eq(a, b). Rather, it executes PartialEq::eq(&a, &b). That is, Rust calls eq() with automatically-referenced operands when using the operator.
So, x == *y is basically (&x).eq(&*y), but x == y is (&x).eq(&y), which uses a double reference for y and therefore doesn't work.
When you write x.eq(y), however, Rust does not perform any adjustment to y (well, almost), but it does borrow x because of autoref. So this is the same as (&x).eq(y), which is the same as the operator version (&x).eq(&*y).
Related
I'm trying to translate some of my C++ code into Rust and came across the following problem. The code is simplified to a (hopefully) minimal not-working example. In the end it is supposed to work with all unsigned integer types, but for this example it just needs to implement the PartialOrd trait.
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![feature(const_trait_impl)]
const fn foo<T>(n: T, k: T) -> T
where
T: Sized,
T: Copy,
T: ~const core::marker::Destruct,
T: ~const std::cmp::PartialOrd,
{
if n < k {
n
} else {
k
}
}
Fails to compile with the following error message:
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
13 | if n < k {
| ^
If I replace the arguments n and k with references, it compiles. Turns out, the functions in the PartialOrd are also implemented using references. So from my understanding, the expression 2 < 4 will call the le function with references. For performance reasons, I doubt that's what's happening, though.
It's actually two questions that I'm asking:
Can I solve the error without using references?
Why is PartialOrd using references while Ord uses values (at least for min and max, but not for cmp)?
Adding #![feature(const_refs_to_cell)] makes it compile.
min and max take Self because they return one of the two arguments as Self. Other methods in Ord and PartialOrd else returns a bool or an Ordering so they can take by reference. if min and max they took by reference the signature would be fn max<'a>(&'a self, other: &'a Self) -> &'a Self which you "get for free" because there is a impl<A> Ord for &A where A: Ord.
This question already has answers here:
Why can't I use `&Iterator<Item = &String>` as an iterator?
(3 answers)
How do I create a function that accepts an iterator of i32s as either values or references and sums them?
(1 answer)
How to write a Rust function that takes an iterator?
(3 answers)
Closed 2 years ago.
I have a function that takes a &Vector<T>. I want to change it to take an iterator in order to run it on different container/collection/slice types.
It produces an error because the function is called twice.
What I Have So Far
fn operate_on_iterator<'a>(iterator: &impl IntoIterator<Item = i32>) -> i32 {
// This is an example. Please don't tell me to use `.sum`.
let mut sum = 0;
for val in iterator.into_iter() {
sum += val;
}
sum
}
fn caller() -> i32 {
let v = vec![1, 2, 3, 4];
let s1 = operate_on_iterator(&v);
let s2 = operate_on_iterator(&v);
s1 + s2
}
playground
The Error I Get
error[E0507]: cannot move out of `*iterator` which is behind a shared reference
--> src/lib.rs:13:16
|
13 | for val in iterator.into_iter() {
| ^^^^^^^^ move occurs because `*iterator` has type `impl IntoIterator<Item = i32>`, which does not implement the `Copy` trait
Restrictions and notes
I do not want to use dyn because I prefer the slightly larger code size over the performance impact of pointer dereferencing. (Although I will use it for now and will benchmark it once I have both traits and trait objects implemented, i.e. after I have an answer to this question.) Also using dyn also didn't work so far for me.
I have used this answer as a basis. How to write a Rust function that takes an iterator?
My Item implements Clone, Binding, and Drop.
I also tried to implement it using Iterator instead of IntoIterator. Also no luck.
Shepmaster linked to the answer.
For completeness, this is the necessary change:
&impl IntoIterator<Item = i32> -->
impl IntoIterator<Item = &'a i32>
Resulting in this code:
fn operate_on_iterator<'a>(iterator: impl IntoIterator<Item = &'a i32>) -> i32 {
// This is an example. Please don't tell me to use `.sum`.
let mut sum = 0;
for val in iterator.into_iter() {
sum += val;
}
sum
}
I came across this issue while experimenting with different ways to solve this question.
I'm trying to define a trait which takes an argument by reference, and returns Self, like this:
struct X {}
trait CopyFrom {
fn copy_from(&x: X) -> Self;
}
The error I get is:
error[E0642]: patterns aren't allowed in functions without bodies
--> src/main.rs:5:18
|
5 | fn copy_from(&x: X) -> Self;
| ^^ pattern not allowed in function without body
If I take x by value it compiles fine (but that would consume the argument, which I don't want).
The Rust reference has this to say:
The kinds of patterns for parameters is limited to one of the
following:
IDENTIFIER
mut IDENTIFIER
_
& IDENTIFIER
&& IDENTIFIER
Beginning in the 2018 edition, function or method parameter patterns
are no longer optional. Also, all irrefutable patterns are allowed as
long as there is a body. Without a body, the limitations listed above
are still in effect.
I was not able to find anything else that would explain why I can't define a trait function that takes an argument by reference.
You're using the wrong syntax here — &x: X is a reference pattern that dereferences the argument of type X; in other words,
fn f(&x: X) {
// ...
}
is equivalent to
fn f(x: X) {
let &x = x;
}
which, in turn, means
fn f(x: X) {
let x = *x;
}
Instead, you want to make the parameter itself a reference:
fn f(x: &X) { // take argument by reference
// ...
}
This question already has answers here:
Temporarily move out of borrowed content
(3 answers)
How do you replace the value of a mutable variable by taking ownership of it?
(2 answers)
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
Closed 3 years ago.
Is there a clean way to implement a safe function g that mutates a mutable reference by applying f on its value without having to implement Clone or Default (or any other special trait) for T? If not, why is or should this not be possible?
Imagine a type T and a function f:
fn f(v: T) -> T;
For example:
fn f(mut v: u32) -> u32 {
v += 1;
v
}
The following code is invalid because p cannot be dereferenced:
fn g(p: &mut T) {
*p = f(*p)
}
I searched and tried many things, but I didn't come up with a safe solution.
For people who are interested for the cases where Clone and Default are allowed:
By implementing Clone you could do:
fn g(p: &mut T) {
*p = f(p.clone())
}
By implementing Default you could do:
fn g(p: &mut T) {
let val = core::mem::take(p);
core::mem::replace(p, f(val));
}
I have the following code:
fn example(known_primes: &[i32], number: i32, prime: i32, limit: i32) {
let mut is_prime = true;
for prime in known_primes {
if number % prime == 0 {
is_prime = false;
break;
}
if *prime > limit {
break;
}
}
}
Why do I need to dereference prime in the second condition (*prime > limit), when I don't need to do so in the first one (number % prime == 0)?
Both % and < are operators that take two numbers and return something. The only difference seems to be in what they return (a number vs. a boolean). While Why isn't it possible to compare a borrowed integer to a literal integer? does explain what would be required to make the code work (implementations for all overloads, ideally in the standard library), it does not say why it does work for a % b. Is there a fundamental difference between these operators? Or is it just not implemented yet?
Comparison operators actually do behave differently than arithmetic operators. The difference becomes obvious when looking at the trait definitions. As an example, here is the PartialEq trait
pub trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { ... }
}
and the Add trait
pub trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
We can see that comparison traits take the operands by reference, while the arithmetic traits take the operands by value. This difference is reflected in how the compiler translates operator expressions:
a == b ==> std::cmp::PartialEq::eq(&a, &b)
a + b ==> std::ops::Add::add(a, b)
The operands of comparisons are evaluated as place expressions, so they can never move values. Operands of arithmetic operators, on the other hand, are evaluated as value expressions, so they are moved or copied depending on whether the operand type is Copy.
As a result of this difference, if we implement PartialEq for the type A, we can not only compare A and A, but also &A and &A by virtue of deref coercions for the operands. For Add on the other hand we need a separate implementation to be able to add &A and &A.
I can't answer why the standard library implements the "mixed" versions for reference and value for arithmetic operators, but not for comparisons. I can't see a fundamental reason why the latter can't be done.
Because you can have Rem implementation for different types and the core library implements
impl<'a> Rem<&'a i32> for i32 { /* … */ }
This is impossible for PartialOrd and Ord traits, so you need to compare exactly the same types, in this case i32, that is why there is requirement for dereference.