Error genérico: parámetro de tipo esperado, estructura encontrada

Comencé un nuevo proyecto, donde quiero ser lo más modular posible, con eso quiero decir que me gustaría poder reemplazar algunas partes con otras en el futuro. Esto parece ser un uso perfecto para los traits , en este momento tengo este código:

 mod parser; mod renderer; mod renderers; use parser::MarkParser; use renderer::MarkRenderer; struct Rustmark 

{ parser: P, renderer: R, } impl

Rustmark

{ fn new() -> Rustmark

{ Rustmark { parser: parser::DefaultParser::new(), renderer: renderers::HTMLRenderer::new(), } } fn render(&self, input: &str) -> &str { self.renderer.render(self.parser.parse(input)) } }

Pero tengo un par de errores, principalmente este:

error: tipos no coincidentes: Rustmark

esperado Rustmark

, found Rustmark (parámetro de tipo esperado, found struct parser::DefaultParser ) [E0308]

Y un par de errores de por vida como este:

error: no se puede inferir un tiempo de vida apropiado para la coacción automática debido a requisitos conflictivos

ayuda: considere usar un parámetro explícito de por vida como se muestra: fn parse(&'a self, input: &'a str) -> &str

He intentado varios ajustes para que funcione, pero ninguno de ellos pareció apaciguar al comstackdor. Así que quería saber si este es el enfoque correcto y qué podría hacer para que funcione.

Primer error: crea un objeto Rustmark con el parser de campo de tipo DefaultParser y el renderer de campo de tipo HTMLRenderer , pero se espera que la función devuelva Rustmark . En general, P no es del tipo DefaultParser y R no es del tipo HTMLRenderer , por lo que nunca se comstackrá. Una buena solución si desea tener valores predeterminados del tipo correcto es enlazar P y R para implementar el trait Default , de esta manera:

 use std::default:Default; impl  Rustmark  { fn new() -> Rustmark  { Rustmark { parser: P::default(), renderer: R:default(), } } } 

Segundo error: ese problema principal es que devuelves una referencia de algo que probablemente morirá dentro del método de render (la String que asignas en el método de render interno probablemente). El comstackdor le dice que no conoce la duración del objeto apuntado por esa referencia, por lo que no puede garantizar que la referencia sea válida. Puede especificar un parámetro de por vida, pero en su caso, probablemente la mejor solución es devolver el objeto String sí mismo, no una referencia.

Siguiendo la respuesta de Andrea P busqué el rasgo por default en el default . Que se define así:

 pub trait Default { fn default() -> Self; } 

Y lo que terminé haciendo no fue usar el rasgo default sino agregar un constructor new en mis rasgos MarkParser y MarkRenderer como este:

 pub trait MarkParser { fn new() -> Self; fn parse(&self, input: &str) -> &str; } 

La pieza clave que no sabía era la palabra clave Self y de esta manera puedo escribir mi implementación de esta manera:

 impl  Rustmark  { fn new() -> Rustmark  { Rustmark { parser: P::new(), renderer: R::new(), } } fn render(&self, input: &str) -> &str { self.renderer.render(self.parser.parse(input)) } } 

Esto es exactamente lo mismo que implementar el rasgo Default , excepto que puedo usar el new lugar del default que prefiero y no tengo que agregar el rasgo Default a la impl de RustMark.

 impl  Rustmark  { 

en lugar de

 impl  Rustmark  { 

Muchas gracias a Andrea P por señalarme en la dirección correcta.