When learning rust closures,I try Like Java return "A Function"
fn equal_5<T>() -> T
where T: Fn(u32) -> bool {
let x:u32 = 5;
|z| z == x
}
But when i use it
let compare = equal_5();
println!("eq {}", compare(6));
Build error
11 | let compare = equal_5();
| ------- consider giving `compare` a type
12 | println!("eq {}", compare(6));
| ^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
See: https://doc.rust-lang.org/stable/rust-by-example/trait/impl_trait.html
Currently T simply describes a type, which in this case implements the Fn trait. In other words, T isn't a concrete type. In fact with closures, it's impossible to declare a concrete type because each closure has it's own unique type (even if two closures are exactly the same they have different types.)
To get around directly declaring the type of the closure (which is impossible) we can use the impl keyword. What the impl keyword does is convert our description of a type (trait bounds) into an invisible concrete type which fits those bounds.
So this works:
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
let compare = equal_5();
println!("eq {}", compare(6));
One thing to note is we can also do this dynamically. Using boxes and the dyn trait. So this also works, however incurs the associated costs with dynamic resolution.
fn equal_5() -> Box<dyn Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}
let compare = equal_5();
println!("eq {}", compare(6));
The compiler seems to be complaining that it's expecting a type parameter but finds a closure instead. It knows the type, and doesn't need a type parameter, but also the size of the closure object isn't fixed, so you can either use impl or a Box. The closure will also need to use move in order to move the data stored in x into the closure itself, or else it wont be accessible after equal_5() returns, and you'll get a compiler error that x doesn't live long enough.
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
or
fn equal_5() -> Box<Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}
This is what the std says:
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used
/// by `==`.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn eq(&self, other: &Rhs) -> bool;
/// This method tests for `!=`.
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn ne(&self, other: &Rhs) -> bool {
!self.eq(other)
}
}
And the link: https://doc.rust-lang.org/src/core/cmp.rs.html#207
This is my code:
fn main() {
let a = 1;
let b = &a;
println!("{}", a==b);
}
and the compiler told me:
error[E0277]: can't compare `{integer}` with `&{integer}`
--> src\main.rs:4:21
|
4 | println!("{}", a==b);
| ^^ no implementation for `{integer} == &{integer}`
|
= help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
But when I used eq(), it compiled:
fn main() {
let a = 1;
let b = &a;
println!("{}", a.eq(b));
}
It's actually quite simple, but it requires a bit of knowledge. The expression a == b is syntactic sugar for PartialEq::eq(&a, &b) (otherwise, we'd be moving a and b by trying to test if they're equal if we're dealing with non-Copy types).
In our case, the function PartialEq::eq needs to take two arguments, both of which are of type &i32. We see that a : i32 and b : &i32. Thus, &b will have type &&i32, not &i32.
It makes sense that we'd get a type error by trying to compare two things with different types. a has type i32 and b has type &i32, so it makes sense that no matter how the compiler secretly implements a == b, we might get a type error for trying to do it.
On the other hand, in the case where a : i32, the expression a.eq(b) is syntactic sugar for PartialEq::eq(&a, b). There's a subtle difference here - there's no &b. In this case, both &a and b have type &i32, so this is totally fine.
The difference between a.eq(b) and a == b in that dot operator does autoref/autoderef on receiver type for call-by-reference methods.
So when you write a.eq(b) compiler looks at PartialEq::eq(&self, other: &Rhs) signature, sees &self reference and adds it to a.
When you write a == b it desugars to PartialEq::eq(a, b) where a: i32 b: &i32 in your case, hence the error no implementation for `{integer} == &{integer}` .
But why it does not do the same in operators? See
Tracking issue: Allow autoderef and autoref in operators (experiment) #44762
Related information:
What are Rust's exact auto-dereferencing rules?
Wikipedia's list of programming languages with algebraic data types (ADTs) suggests that Rust indeed has ADTs, but I am not sure if my interpretation for why this is true for Rust is correct. As I understand it, to say that one has ADTs one needs to have:
Values:
Zero (or Void) - ! in Rust) - a type that gets no value.
One (or Unit) - () in Rust) - a type that gets one value: () itself.
Operations:
Addition - enum { A, B } in Rust - operation that can return the values of A or the values of B.
Multiplication - Tuple (A, B) in Rust - operation that can return all the combinations of A and B.
Rules:
a + b = b + a: enum { A, B } =~ enum { B, A }
a * b = b * a: (A, B) =~ (B, A)
0 + x = x: enum { !, A } =~ enum { A }
0 * x = 0: (!, A) =~ !
1 * x = x: ((), A) =~ A
Here A =~ B means that there is a fn(A) -> B and fn(B) -> A
Is my description above for why Rust's type system supports ADTs true, or am I missing or misunderstanding something about it?
Is my description above for why Rust's type system supports ADTs true, or am I missing or misunderstanding something about it?
Yes, this is about right. One change I would make is to express Void as an enum. As interjay said in the comments, ! is not part of stable Rust (yet):
enum Void {} // uninhabited
The rest follows easily, and I'm not sure that an answer could express it better than you have done yourself in your question.
I am new to both Haskell and Rust and am attempting to translate Haskell code into Rust so as to compare the features that support genericity. However, it seems I either need help with syntax or some fundamental concepts in Rust.
I have this code in Haskell:
class HasEmpty a where
empty :: a
isEmpty :: a -> Bool
class Hashable a where
hash :: a -> Int
class (HasEmpty x, Hashable (Element x))
=> Hashset x where
type Element x
size :: x -> Int
The important part is at the bottom where we define a type class named Hashset which takes a single parameter x and sub-classes HasEmpty. The body of the type class defines an associated type, which is required to be Hashable, and an associated method size.
How can I do the same thing in Rust? Here is what I've written thus far:
trait HasEmpty {
fn empty(&self);
fn is_empty(&self) -> bool;
}
trait Hashable {
fn hash(&self) -> u32;
}
trait Hashset<E>
where E: Hashable
{
fn size(&self) -> i32;
}
This compiles and allows me to say that the associated type E is Hashable, but how can I 'inherit' the 'trait methods' of HasEmpty by using it as a supertrait? I know this is possible by saying:
trait Hashset: HasEmpty {
fn size(&self) -> i32;
}
but is it possible to both constrain the associated type and use a supertrait? Perhaps I am asking the wrong question.
is it possible to both constrain the associated type and use a supertrait?
Sure, I'm not sure why you didn't just combine the two syntaxes:
trait Hashset<E>: HasEmpty
where E: Hashable
{
fn size(&self) -> i32;
}
However, you should know that E is not an associated type, it's just a generic type. See When is it appropriate to use an associated type versus a generic type? for more info.
An associated type would be:
trait Hashset: HasEmpty {
type E: Hashable;
fn size(&self) -> i32;
}
I have a newtype and I want to implement Ord:
use std::cmp::{Ord, Ordering};
struct MyType(isize);
impl Ord for MyType {
fn cmp(&self, &other: Self) -> Ordering {
let MyType(ref lhs) = *self;
let MyType(ref rhs) = *other;
lhs.cmp(rhs)
}
}
When I try to compare two variables of my types, I get errors:
error[E0277]: the trait bound `MyType: std::cmp::PartialOrd` is not satisfied
--> src/main.rs:5:6
|
5 | impl Ord for MyType {
| ^^^ can't compare `MyType` with `MyType`
|
= help: the trait `std::cmp::PartialOrd` is not implemented for `MyType`
error[E0277]: the trait bound `MyType: std::cmp::Eq` is not satisfied
--> src/main.rs:5:6
|
5 | impl Ord for MyType {
| ^^^ the trait `std::cmp::Eq` is not implemented for `MyType`
When I implement PartialEq, Eq and PartialOrd (gt(), lt(), eq(), ge(), le(), etc.), everything works fine, but if I provided cmp, we can infer functions like lt() and eq()! This is redundant! I don't like this!
When looking in the docs, I see this in the definition of Ord:
pub trait Ord: Eq + PartialOrd<Self>
This looks like the trait inherits from Eq and PartialOrd.
Why can't the trait provide default implementations for the required methods from the inherited traits using the cmp function?
I don't know how inheritance of traits works and searching turned up nothing useful, but I think this is something that should be possible.
How is this done in Rust? I hope not this way...
For your specific case I'd use #[derive]:
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct MyType(isize);
fn main() {
let a = MyType(5);
let b = MyType(6);
println!("{:?}", a.cmp(&b))
}
If you need to special case your Ord implementation, you still have to write out that code, there's nothing that can save us there! You can still derive implementations for the other traits, if it makes sense to do so.
The other part of your question is ambiguous, so I'll answer it both ways I read it:
Why can't Ord be automatically provided by anything with PartialOrd?
Let's look at the docs for PartialOrd and Ord.
PartialOrd says: "The comparison must satisfy antisymmetry and transitivity", while Ord says: "types that form a total order". These are math terms and I won't do as good a job as Wikipedia will at describing them.
However, we can use floating point numbers as an example. Floats have a special value called NaN. Comparing against this value is tricky. For example, all of 1.0 < NaN, 1.0 == NaN and 1.0 > NaN are false! These don't form a total order, but we can still compare one value against another. This is why PartialOrd exists - to allow us to compare types like this. incidentally, PartialEq exists for similar reasons.
We can't define Ord in terms of PartialOrd because we don't have the appropriate guarantees about the underlying types. This is Rust's type system saving us from making a mistake!
Why can't PartialOrd be automatically provided by anything with Ord?
The problem here is that more types are PartialOrd than they are Ord. If we required everything to be Ord, then we couldn't have any floating point comparisons, because they don't have a total order, or we'd have to give up on having a total order and losing out on the safety that it provides.
However, there have been ideas to automatically do this for derive. Proposed RFC 2385 would allow the above code to be reduced to:
#[derive(Debug, Copy, Eq, Ord)]
struct MyType(isize);
when I implement PartialOrd (gt(), lt(), eq(), ge(), le() ...)
Note that PartialOrd does have default implementations, you only need to implement partial_cmp. The others are there for ease-of-use or possibly performance reasons.
Please consider this as an addendum to the original answers, which are suited for your specific case. This answer deals with the second part of your question.
Consider this struct:
struct Person {
id: u32,
name: String,
height: u32,
}
Equality: the PartialEq and Eq traits
PartialEq Trait, From the docs
Trait for equality comparisons which are partial equivalence
relations. This trait allows for partial equality, for types that do not
have a full equivalence relation. For example, in floating point numbers
NaN != NaN, so floating point types implement PartialEq but not Eq.
Formally, the equality must be (for all a, b and c):
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.
So if you want to express what it means for values of your types to be equal, you must implement the PartialEq trait. Implementing it allows us to write x == y and x != y for our types.
impl PartialEq for Person {
fn eq(&self, other: &Person) -> bool {
self.height == other.height
}
}
Note that we are deciding the equality of Person struct just on the basis of the heights. You could also have implemented this eq method if you want to compare every struct field:
fn eq(&self, other: &Person) -> bool {
self.id == other.id && self.name == other.name && self.height == other.height
}
But it would be easier to simply add #[derive(PartialEq)] if that's the behavior you want.
Eq Trait, From the Docs
Trait for equality comparisons which are equivalence relations.
This means, that in addition to a == b and a != b being strict inverses,
the equality must be (for all a, b and c):
reflexive: a == a;
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.
This property cannot be checked by the compiler, and therefore Eq implies
PartialEq, and has no extra methods.
Derivable
This trait can be used with #[derive]. When derived, because Eq has no extra methods,
it is only informing the compiler that this is an equivalence relation rather than a
partial equivalence relation. Note that the derive strategy requires all
fields are Eq, which isn't always desired.
PartialEq is for relations which are not necessarily reflexive (i.e. there can be such x that x != x) and that Eq is a marker trait which says that relation is also reflexive (and now it is a proper equivalence relation).
You can also implement the Eq trait manually with an empty impl block
impl Eq for Person {}
But, again, it’s easier to add Eq to your #[derive(Eq)] list.
Ordering: the PartialOrd and Ord traits
The relative ordering of values is calculated using the operators <, <=, >= and >. To implement these for your own types, you must implement the PartialOrd trait.
Before you can implement PartialOrd, you must implement PartialEq.
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Ordering is an enum with these values:
pub enum Ordering {
Less,
Equal,
Greater,
}
partial_cmp returns an Option and not an Ordering because there are types of which values cannot always be compared, such as floating-point numbers. NaNs are not representable numbers; expressions such as 3.0 < NaN don’t make any sense. In those cases, partial_cmp returns None. Floating-point values are the only case in the standard library where this happens. More can be found here.
The fact that partial_cmp returns an Option<Ordering> has a consequence: it might not be possible to place two values, x and y, into a definite order. In practice, this means that implementing PartialOrd is not sufficient to make your values sortable. You also need to implement the Ord trait.
Before you can implement Ord, you must first implement PartialOrd, Eq and PartialEq.
For our Person struct, again we can delegate down to one of our member variables:
impl Ord for Person {
fn cmp(&self, other: &Person) -> Ordering {
self.height.cmp(&other.height)
}
}
For starters, you can implement only PartialOrd::partial_cmp, as lt, le, gt, and ge have default implementations. Furthermore, if you implement Ord, you can simply implement cmp as usual and partial_cmp becomes just Some(self.cmp(other)).
However, if you only want to delegate to some field's notion of equality and ordering, then it's far better and easier to derive:
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct MyType(isize);