Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doesn't have a size known at compile-time

Tags:

rust

use std::fmt::Debug;

#[derive(Debug)]
struct Node<K: Debug, V: Debug> {
    key: K,
    value: V,
}

fn myprint<K: Debug + ?Sized, V: Debug + ?Sized>(node: &Node<K,V>) -> String {
    return format!("{:?}: {:?}", node.key, node.value);
}

fn main() {
    let node = Node{key: "xxx", value: "yyy"};
    myprint(&node);
}

compile error:

error[E0277]: the size for values of type `K` cannot be known at compilation time
  --> src/main.rs:22:50
   |
17 | struct Node<K: Debug,V: Debug> {
   |             - required by this bound in `Node`
...
22 | fn myprint<K:Debug+?Sized, V:Debug+?Sized>(node: &Node<K,V>) -> String {
   |            -                                     ^^^^^^^^^^ doesn't have a size known at compile-time
   |            |
   |            this type parameter needs to be `std::marker::Sized`

But the following code works:

use std::fmt::Debug;

fn debug<T: Debug + ?Sized>(t: &T) { // T: Debug + ?Sized
    println!("{:?}", t);
}

fn main() {
    debug("my str"); // T = str, str: Debug + ?Sized ✔️
}
like image 496
Anunaki Avatar asked Jan 24 '23 18:01

Anunaki


1 Answers

All type parameters are implicitly Sized.

That means that struct Node<K: Debug, V: Debug> {...} is the same as struct Node<K: Debug + Sized, V: Debug + Sized> {...}.

In order to allow the Sized bound to be removed, a special syntax ?Sized was added. This means that a type parameter is optionally not Sized.

In function myprint<K:Debug + ?Sized, V:Debug + ?Sized>, you were allowing K to be not Sized. Meanwhile, K in Node<K,V> must be Sized. This means that there are type parameters which myprint allows but which will cannot be compiled.

The exact same problem also applies to V.


how to resolve this problem

Well, the first question is do you need to support ?Sized as a K or V in a Node? If not, your function doesn't need to support it either.

fn myprint<K: Debug, V: Debug>(node: &Node<K,V>) {...}

If on the other hand you plan to support ?Sized K/V, you need to define your struct correctly:

struct Node<K: Debug + ?Sized, V: Debug + ?Sized> {...}

but fn debug<T: Debug+?Sized>(t: &T) can works!

Yep. That is a valid signature. The reason it doesn't work in the other function is the other function says K, a type defined as Debug + ?Sized needs to be used in Node<K, V> which is a Debug + Sized (no question mark) context.

like image 195
Stephen Weinberg Avatar answered Feb 16 '23 02:02

Stephen Weinberg