Знак привязки "T: std :: fmt :: Display" не выполняется

108
7

Я пишу основную двоичную древовидную структуру, и я хочу отобразить узел. Кажется, что у Rust проблемы с отображением общего типа, и я получаю эту ошибку:

error[E0277]: the trait bound 'T: std::fmt::Display' is not satisfied
--> src/main.rs:55:60
|
55 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait 'T: std::fmt::Display' not satisfied
|
= help: consider adding a 'where T: std::fmt::Display' bound
= note: required by 'std::fmt::Display::fmt'

error[E0277]: the trait bound 'T: std::fmt::Display' is not satisfied
--> src/main.rs:62:60
|
62 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait 'T: std::fmt::Display' not satisfied
|
= help: consider adding a 'where T: std::fmt::Display' bound
= note: required by 'std::fmt::Display::fmt'

Здесь полный код, включая итераторы

struct Node<T> {
data: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}

struct NodeIterator<T> {
nodes: Vec<Node<T>>,
}

struct Tree<T> {
root: Option<Node<T>>,
}

impl<T> Node<T> {
pub fn new(value: Option<T>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>)
-> Node<T> {
Node {
data: value.unwrap(),
left: left,
right: right,
}
}

pub fn insert(&mut self, value: T) {
println!("Node insert");
match self.left {
Some(ref mut l) => {
match self.right {
Some(ref mut r) => {
r.insert(value);
}
None => {
self.right = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
None => {
self.left = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
}

impl<T> std::fmt::Display for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}

impl<T> std::fmt::Debug for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}

impl<T> Iterator for NodeIterator<T> {
type Item = Node<T>;
fn next(&mut self) -> Option<Node<T>> {
if self.nodes.len() == 0 {
None
} else {
let current: Option<Node<T>> = self.nodes.pop();
for it in current.iter() {
for n in it.left.iter() {
self.nodes.push(**n);
}
for n in it.right.iter() {
self.nodes.push(**n);
}
}
return current;
}
}
}

impl<T> Tree<T> {
pub fn new() -> Tree<T> {
Tree { root: None }
}

pub fn insert(&mut self, value: T) {
match self.root {
Some(ref mut n) => {
println!("Root is not empty, insert in node");
n.insert(value);
}
None => {
println!("Root is empty");
self.root = Some(Node::new(Some(value), None, None));
}
}
}

fn iter(&self) -> NodeIterator<T> {
NodeIterator { nodes: vec![self.root.unwrap()] }
}
}

fn main() {
println!("Hello, world!");

let mut tree: Tree<i32> = Tree::new();
tree.insert(42);
tree.insert(43);

for it in tree.iter() {
println!("{}", it);
}
}

спросил(а) 2021-01-25T17:18:59+03:00 4 месяца, 4 недели назад
1
Решение
117

Вот минимальная версия этой проблемы:

struct Bob<T>(T);

impl<T> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}

fn main() {
let x = Bob(4);
println!("{}", x);
}

Давайте взглянем на нашу функцию fmt:

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}

Мы можем переписать его следующим образом для лучшей ясности:

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: ")?;
std::fmt::Display::fmt(&self.0, f)
}

Вызов одного из макросов форматирования (write! format! println! т.д.) С двойными скобками в кавычках "{}" говорит, чтобы вызвать функцию fmt из self.0 Display для этого аргумента (self.0 в этом случае).

Проблема в том, что у нас есть некоторый общий тип T, поэтому компилятор понятия не имеет, реализован ли Display для него или нет.

Есть два способа исправить это.

Во-первых, мы могли бы добавить ограничение T: std::fmt::Display на нашу реализацию Display for Bob. Это позволит нам использовать структуру с типами Display non-, но Display будет реализовано только тогда, когда мы будем использовать его с типами Display.

Это исправление выглядит так:

impl<T: std::fmt::Display> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}

Во-вторых, мы могли бы добавить это ограничение к определению структуры, например:

struct Bob<T: std::fmt::Display>(T);

Это будет означать, что Bob является только общим в отношении типов, которые Display. Это более ограничивает и ограничивает гибкость Bob, но могут быть случаи, когда это необходимо.

Есть другие черты, похожие на Display которые можно вызвать, поместив в маркеры разные маркеры. Полный список можно найти в документации, но, например, мы могли бы использовать свойство Debug с

write!(f, "Bob: {:?}", self.0)

только тогда нам нужно будет убедиться, что T является std::fmt::Debug.

ответил(а) 2021-01-25T17:18:59+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема