2

I'd like this program to compile and print 314158 when executed:

extern crate num;

use num::{BigInt, FromPrimitive, One};

fn main() {
    let p: BigInt = FromPrimitive::from_usize(314159).unwrap();
    let q: BigInt = p - One::one();
    println!("q = {}", q);
} // end main

The compiler error is:

error[E0284]: type annotations required: cannot resolve `<num::BigInt as std::ops::Sub<_>>::Output == num::BigInt`
 --> src/main.rs:7:23
  |
7 |     let q: BigInt = p - One::one();
  |                       ^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user3134725
  • 1,003
  • 6
  • 12

1 Answers1

5

Rust follows an open world hypothesis when it comes to traits. It knows, based on your annotations, that p is BigInt. It also knows that One::one() has a type which implements One. So Rust is looking for a subtraction operator on BigInt which takes a One-like thing as an argument.

num::BigInt as std::ops::Sub<Foo>>

where Foo implements One. Trouble is, BigInt implements Sub in several different ways, so Rust doesn't know whether you're trying to subtract a i32, a u64, or another BigInt from p.

One answer is to be more explicit with your types.

let p: BigInt = FromPrimitive::from_usize(314159).unwrap();
let one: BigInt = One::one();
let q: BigInt = p - one;

However, more succinctly, you may take advantage of the fact that BigInt implements One and help the compiler with type inference that way.

let p: BigInt = FromPrimitive::from_usize(314159).unwrap();
let q: BigInt = p - BigInt::one();

(Thanks, @loganfsmyth, for this latter solution!)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • Thanks. I was hoping that there was a more succinct way than declaring `one` as your solution does. – user3134725 Jul 17 '18 at 01:02
  • I'm still somewhat new to Rust myself, to be entirely honest, so I don't know all of the ins and outs. I'm a Haskeller by trade, so I approached this from a type-resolution perspective. – Silvio Mayolo Jul 17 '18 at 01:03
  • 1
    The types are redundant. `let p = BigInt::from_usize(314159).unwrap(); let q = p - BigInt::one();`. – Shepmaster Jul 17 '18 at 01:10