I'm trying to implement a generic struct that can take any type parameter.
struct Position<T>{
x: T,
y: T,
}
impl<T:Num> Position<T>{
fn add(&self, other: &Position<T>) -> Box<Position<T>>{
box Position{x:self.x + other.x, y:self.y + other.y}
}
fn display(&self) -> String{
"WELCOME ".to_string()
}
}
now I can define
let original_position = Position::<int>{x: 2, y:23};
let another_postion = original_position.add(&original_position);
let welcome = original_postion.display();
without any error
similarly, i can do the following without any error.
let string_position = Position::<String>{x: "x_pos".to_string(), y: "y_pos".to_string()};
now due to the Num trait constraint i cannot call the following (which is obvious ).
string_position.add(&original_position);
but,my problem is that now i cannot call the following because of the same Num trait constraint
string_position.display()
the above function has noting to do with Num type, it simply returns the string "WELCOME"
how do i need to rewrite the implemetation so that add method can be called only by Position<Num> and display can be called by any other generic implementation.
You should create separate implementations, one with the bound and the other without, like this:
impl<T:Num> Position<T>{
fn add(&self, other: &Position<T>) -> Box<Position<T>>{
box Position{x:self.x + other.x, y:self.y + other.y}
}
}
impl<T> Position<T>{
fn display(&self) -> String{
"WELCOME ".to_string()
}
}
You can see that it works here.
Related
I'm learning Rust, (coming from Java) and decided to write a Chess Engine in Rust (as I previously have in Java) to get used to the language.
I've made structs for different types of chess moves (Slide, Passant, Castle, etc), each of which implements the Move trait. Here is an example:
pub struct PawnPush{
indices: [i8; 2],
befores: [i8; 2],
afters: [i8; 2],
passant_before: i8,
}
impl PawnPush{
pub fn new(from_index: i8, passant_square: i8) -> Self{
if from_index < 32{
Self{
indices: [from_index, from_index + 16],
befores: [piece::WP, piece::__],
afters: [piece::__, piece::WP],
passant_before : passant_square,
}
}
else{
Self{
indices: [from_index, from_index - 16],
befores: [piece::BP, piece::__],
afters: [piece::__, piece::BP],
passant_before : passant_square,
}
}
}
}
impl Move for PawnPush{
fn indices(&self) -> &[i8]{
return &(self.indices);
}
fn befores(&self) -> &[i8]{
return &(self.befores);
}
fn afters(&self) -> &[i8]{
return &(self.afters);
}
fn is_capture(&self) -> bool{
return false;
}
fn is_reversible(&self) -> bool{
return false;
}
fn passant_before(&self) -> i8{
return self.passant_before;
}
fn passant_after(&self) -> i8{
return if self.indices[0] < 32 {self.indices[0] + 8} else {self.indices[0] - 8};
}
fn get_name(&self) -> String{
return "".to_string();
}
fn moves_king(&self) -> bool{
return false;
}
}
The idea is that the Board can iterate through indices, befores, and afters of any move to implement them.
I've read through https://doc.rust-lang.org/book/ch17-02-trait-objects.html, and following that, I have some functions defined as such.
pub fn get_moves(&self) -> Vec<Box<dyn Move>>
pub fn take_move(&mut self, m : &impl Move)
The question is: How can I get an element from the vector returned from the first function to be given to the second function?
Like, if I do:
fn main() {
let mut b = Board::new(true);
let m = chess_move::PawnPush::new(12, -1);
b.take_move(&m);
b.print_board();
}
This works just fine.
Yet if I try something like:
fn main() {
let mut b = Board::new(true);
let m = b.get_moves()[0];
b.take_move(&m);
b.print_board();
}
I am met with a compilation error:
error[E0277]: the trait bound `Box<dyn Move>: Move` is not satisfied
--> board.rs:143:14
|
143 | b.take_move(&m);
| --------- ^^ the trait `Move` is not implemented for `Box<dyn Move>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Move`:
Castle
KingMove
Passant
PawnPush
Slide
note: required by a bound in `Board::take_move`
--> board.rs:101:40
|
101 | pub fn take_move(&mut self, m : &impl Move){
| ^^^^ required by this bound in `Board::take_move`
Yet, I can still otherwise treat elements of b.get_moves() as if it did impl Move - I can call the methods from Move on m., such as:
fn main() {
let mut b = Board::new(true);
for m in b.get_moves(){
println!("{}",m.is_capture());
}
}
The Rust docs even have this example:
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
It seems strange to me that I can otherwise treat elements of b.get_moves() as if it did impl Move but I can't give it's reference to a function that wants a &impl Move. I'd greatly appreciate an explanation of what Box is/does, as I couldn't really find much about it online.
Additionally, I'm also open to any suggestions if my entire approach is wrong and I shouldn't be handling things in this way. Again, most of my programming experience is in Java, so maybe I'm trying to force OOP where it's not needed.
b.get_moves() returns Vec<Box<dyn Move>>. Therefore, b.get_moves()[0] returns Box<dyn Move>. This type does not implement Move itself, because you haven't written such implementation.
However, Box implements Deref, and as such can behave in many ways "as if" it was the inner type. The meaning of Deref is that you can use the * operator on it: for example, &*b.get_moves(0)[0] will give you &dyn Move, which is what you want. However, as Rust "auto-derefs" method calls, in other words, calls * as many times as needed automatically, you can call methods of Move directly on Box<dyn Move>, without the need to do (*v).method().
Suppose I have the following type in Rust:
type UnOp = fn(u64) -> u64;
That type allows me to create different unary operations:
const add1 : UnOp = |x| x + 1;
const mul2 : UnOp = |x| x * 2;
Now, suppose that I needed add2, add3, add4 (...), for different numbers, in different places of my code. Writing all definitions would be cumbersome, so, instead, I write a generic adder function:
fn adder(add : u64) -> UnOp {
|x| x + add
}
This would allow me to write add(2), add(3), etc., for any number:
// Prints 2 + 40
println!("result is: {}", adder(2)(40))
The problem is: adder is actually not valid Rust code, since |x| ... is a closure, not a static function. In order for adder to work as I want, I need to modify UnOp to be a closure instead:
type UnOp = Box<dyn Fn(u64) -> u64>;
fn adder(add : u64) -> UnOp {
Box::new(move |x| x + add)
}
The problem is: what if I know every usage of adder(N) is applied to a static value?
In that case, creating dynamic closures would be wasteful, computation-wise. Not only that, Box<dyn ...> greatly complicates the code, and may even need lifetime annotations. My question is:
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
Logically, there is no reason it shouldn't be possible, as long as the arguments of adder are static, Rust should be able to just expand it at compile time, to generate each particular instance.
Edit: additional details
A great solution, proposed by #Netwave's answer, is to use Generic consts, which solves this problem for the specific example I gave. Sadly, it doesn't work in case UnOp is polymorphic, or if the constant argument is itself a function:
type UnOp<A> = fn(A) -> A;
pub fn adder<const ADD: u64>() -> UnOp<u64> {
|x| ADD + x
}
pub fn apply<A, const op : UnOp<A>, const x : A>() -> A {
return op(x);
}
This raises 2 errors:
- the type of const parameters must not depend on other generic parameters
- using function pointers as const generic parameters is forbidden
You can do it using const Generics:
type UnOp = fn(u64) -> u64;
const fn adder<const ADD: u64>(x: u64) -> u64 {
ADD + x
}
fn main() {
let add_1: UnOp = adder::<1>;
println!("{}", add_1(1));
}
Playground
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
Since you don't explain why I will ignore this requirement. As I think you limit you option for nothing.
You could prefer a clever use of generic and trait:
trait UnOp {
fn call(&self, _: u64) -> u64;
}
impl<F> UnOp for F
where
F: Fn(u64) -> u64,
{
fn call(&self, x: u64) -> u64 {
self(x)
}
}
fn adder(add: u64) -> impl UnOp {
move |x| x + add
}
fn main() {
fn calculate_two_numbers<T:Debug, const N: usize>(data_set: [T;N]) -> (i32,i32) {
// Key Code
let a = &data_set[0]+&data_set[1];
println!("{:?},{:?},{:?}",&data_set[0],&data_set[1],a);
// Ignore
return (0,0)
}
let data = [1509,1857,1736,1815,1576];
let result = calculate_two_numbers(data);
}
I have a very simple function which takes a list of size n.
From this list, I want to take the first two variables and add them together. I then want to print all of them out with println!.
However, I get the error error[E0369]: cannot add &T to &T
This is the solution the complier suggests but I have trouble understanding it
fn calculate_two_numbers<T:Debug + std::ops::Add<Output = &T>, const N: usize>(data_set: [T;N])
Can someone explain what std::ops::Add<Output = &T> does?
In Rust, when using generic types, you need to tell the compiler what kind of operations you would want to do with the type. This is done be constraining the bounds of your type (You are already using it with Debug, it means you can use it as it were a debug type).
The compiler suggest to add the Add trait, but it will not really work straight away because of the references. You can either add a lifetime or use Copy (with would be probably desirable if you are gonna work with numbers), again add it as another bound:
use std::fmt::Debug;
use std::ops::Add;
fn calculate_two_numbers<T: Debug + Add::<Output=T> + Copy, const N: usize>(data_set: [T; N]) -> (i32, i32) {
// Key Code
let a = data_set[0] + data_set[1];
println!("{:?},{:?},{:?}", data_set[0], data_set[1], a);
// Ignore
return (0, 0);
}
fn main() {
let data = [1509, 1857, 1736, 1815, 1576];
let result = calculate_two_numbers(data);
}
Playground
If using the references approach, you need to specify that for any lifetime for your references that reference implements Add<Output=T>:
fn calculate_two_numbers<T: Debug, const N: usize>(data_set: [T; N]) -> (i32, i32)
where
for<'a> &'a T: Add<Output = T>,
{
// Key Code
let a = &data_set[0] + &data_set[1];
println!("{:?},{:?},{:?}", data_set[0], data_set[1], a);
// Ignore
return (0, 0);
}
Playground
In the following program (play), the FooBar trait provides the bar method, but the actual type of the object returned by bar seems to be hidden. If I use a type argument instead of an associated type, it works (play).
Why are associated types treated differently? Or am I doing it wrong?
use std::ops::DerefMut;
pub trait FooBar: Sized {
type Assoc: Sized + DerefMut<Target=Self>;
fn foo(&mut self) -> Option<Self::Assoc>;
fn bar(mut this: Self::Assoc) -> Result<Self::Assoc, Self::Assoc> {
unimplemented!()
}
}
#[derive(Debug)]
struct Test(u32);
impl FooBar for Test {
type Assoc = Box<Test>;
fn foo(&mut self) -> Option<Self::Assoc> {
unimplemented!()
}
}
fn main() {
let mut tt = Test(20);
let tt_foo: Box<Test> = tt.foo().unwrap(); // this is ok
let tt_bar: Box<Test> = FooBar::bar(Box::new(tt)).unwrap(); // but not this
assert_eq!(tt_bar.0, 20);
}
If your method is
fn bar(mut this: Self::Assoc) -> Result<Self::Assoc, Self::Assoc>
and you try to call it with
FooBar::bar(Box::new(tt))
how is Rust supposed to know what type Self is? Box::new(tt) is Self::Assoc right, but you can’t get Self from that, several types could have the same Assoc.
And that’s what rustc is complaining about:
type annotations required
You’d have to annotate what type Self is:
let tt_bar: Box<Test> = <Test as FooBar>::bar(Box::new(tt)).unwrap();
or equivalently:
let tt_bar: Box<Test> = Test::bar(Box::new(tt)).unwrap();
The problem is you are trying to access the associated type from the trait. You can only access it from a type that implements the trait, such as from Test:
let tt_bar: Box<Test> = Test::bar(Box::new(tt)).unwrap();
FooBar::Assoc is not a concrete type, so you cannot use it. When you implemented FooBar for Test, you gave Test::Assoc a concrete type, which is accessible:
type Assoc = Box<Test>;
In the code with the generic type, a new copy of FooBar::bar was created with a concrete type. Because you requested a Box<Test>, the new function's signature would be this:
fn bar(mut this: Box<Test>) -> Result<Box<Test>, Box<Test>>
Box<Test> is a concrete type, so it works.
Note: This question was asked before Rust's first stable release. There have been lots of changes since and the syntax used in the function is not even valid anymore. Still, Shepmaster's answer is excellent and makes this question worth keeping.
Finally unboxed closures have landed, so I am experimenting with them to see what you can do.
I have this simple function:
fn make_adder(a: int, b: int) -> || -> int {
|| a + b
}
However, I get a missing lifetime specifier [E0106] error. I have tried to fix this by changing the return type to ||: 'static -> int, but then I get another error cannot infer an appropriate lifetime due to conflicting requirements.
If I understand correctly, the closure is unboxed so it owns a and b. It seems very strange to me that it needs a lifetime. How can I fix this?
As of Rust 1.26, you can use impl trait:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
move |b| a + b
}
fn main() {
println!("{}", make_adder(1)(2));
}
This allows returning an unboxed closure even though it is impossible to specify the exact type of the closure.
This will not help you if any of these are true:
You are targeting Rust before this version
You have any kind of conditional in your function:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
if a > 0 {
move |b| a + b
} else {
move |b| a - b
}
}
Here, there isn't a single return type; each closure has a unique, un-namable type.
You need to be able to name the returned type for any reason:
struct Example<F>(F);
fn make_it() -> Example<impl Fn()> {
Example(|| println!("Hello"))
}
fn main() {
let unnamed_type_ok = make_it();
let named_type_bad: /* No valid type here */ = make_it();
}
You cannot (yet) use impl SomeTrait as a variable type.
In these cases, you need to use indirection. The common solution is a trait object, as described in the other answer.
It is possible to return closures inside Boxes, that is, as trait objects implementing certain trait:
fn make_adder(a: i32) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |b| a + b)
}
fn main() {
println!("{}", make_adder(1)(2));
}
(try it here)
There is also an RFC (its tracking issue) on adding unboxed abstract return types which would allow returning closures by value, without boxes, but this RFC was postponed. According to discussion in that RFC, it seems that some work is done on it recently, so it is possible that unboxed abstract return types will be available relatively soon.
The || syntax is still the old boxed closures, so this doesn't work for the same reason it didn't previously.
And, it won't work even using the correct boxed closure syntax |&:| -> int, since it is literally is just sugar for certain traits. At the moment, the sugar syntax is |X: args...| -> ret, where the X can be &, &mut or nothing, corresponding to the Fn, FnMut, FnOnce traits, you can also write Fn<(args...), ret> etc. for the non-sugared form. The sugar is likely to be changing (possibly something like Fn(args...) -> ret).
Each unboxed closure has a unique, unnameable type generated internally by the compiler: the only way to talk about unboxed closures is via generics and trait bounds. In particular, writing
fn make_adder(a: int, b: int) -> |&:| -> int {
|&:| a + b
}
is like writing
fn make_adder(a: int, b: int) -> Fn<(), int> {
|&:| a + b
}
i.e. saying that make_adder returns an unboxed trait value; which doesn't make much sense at the moment. The first thing to try would be
fn make_adder<F: Fn<(), int>>(a: int, b: int) -> F {
|&:| a + b
}
but this is saying that make_adder is returning any F that the caller chooses, while we want to say it returns some fixed (but "hidden") type. This required abstract return types, which says, basically, "the return value implements this trait" while still being unboxed and statically resolved. In the language of that (temporarily closed) RFC,
fn make_adder(a: int, b: int) -> impl Fn<(), int> {
|&:| a + b
}
Or with the closure sugar.
(Another minor point: I'm not 100% sure about unboxed closures, but the old closures certainly still capture things by-reference which is another thing that sinks the code as proposed in the issue. This is being rectified in #16610.)
Here's how to implement a closure based counter:
fn counter() -> impl FnMut() -> i32 {
let mut value = 0;
move || -> i32 {
value += 1;
return value;
}
}
fn main() {
let mut incre = counter();
println!("Count 1: {}", incre());
println!("Count 2: {}", incre());
}