Cannot apply right shift (>>) on a generic type

Here's a function with generic types, it receive a T and right shit(>>) it. At first I wrote like this:

fn test<T>(v : T) -> T {
    v >> 1
}

It is off cause not compiled, the T need to be restricted on some traits which has method to do the shifting, and the compiler helped me as blew:

error[E0369]: no implementation for `T >> {integer}`
 --> src/main.rs:8:7
  |
8 |     v >> 1
  |     - ^^ - {integer}
  |     |
  |     T
  |
help: consider restricting type parameter `T`
  |
7 | fn test<T: std::ops::Shr<Output = {integer}>>(v : T) -> T {
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

but when I do as the compiler said, another error occurred:

error: cannot constrain an associated constant to a value
 --> src/main.rs:7:26
  |
7 | fn test<T: std::ops::Shr<Output = {integer}>>(v : T) -> T {
  |                          ------^^^---------
  |                          |        |
  |                          |        ...cannot be constrained to this value
  |                          this associated constant...

I'm confused about some place:

  1. What is a {integer} type? I'v never seen the integer sounded by curly brackets.

  2. Isn't Output a "associated type"? Why the compiler said it is a "associated constant"? (To me, associated constant is some sort like const NAN: Self;)

  3. How to write to make my code works?

There is no {integer} type. It's a placeholder the compiler uses in errors for integers whose type it hasn't decided on yet. As for Output, it is an associated type — the compiler is just confused about the invalid syntax {integer} you tried to compare it to, thinking it was some sort of expression that should evaluate to a value.

To get your code to work as written, you can do this:

use std::ops::Shr;

fn test<T: Shr<usize, Output = T>>(v : T) -> T {
    v >> 1
}

Here I specified that the type T must implement Shr with the right-hand-side being usize and the output again being T. I chose usize as most integers implement Shr with an usize. I also required the output type of the operation to be the same type T.

You can also allow the output to be any other type like this:

use std::ops::Shr;

fn test<T: Shr<usize>>(v : T) -> <T as Shr<usize>>::Output {
    v >> 1
}

The syntax I used for the output means "whatever the associated type Output is in the impl Shr<usize> for T".

6 Likes

Thanks so much.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.