for autoref due to conflicting requirements
собственно код: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=2cac758c957e574d1560544cf337496b
не пойму где ошибся.
for autoref due to conflicting requirements
собственно код: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=2cac758c957e574d1560544cf337496b
не пойму где ошибся.
А в трейте RawHoldingRegisters
точно лайфтайм нужен? Если его убрать все будет работать.
Дело в том что при реализации, RawData будет мутабельным заимствованием RawHoldingRegister, а поскольку RawHoldingRegister является ассоциативным типом, то время жизни нужно задекларировать
Можно конечно добавить вж в HoldingRegisters
:
pub trait HoldingRegisters<'a> {
fn get<A: Into<u16>>(&'a mut self, addr: A) -> Result<u16>;
Из примера необходимость такого засорения лайфтаймами не очевидна.
Еще можно можно поменять методы в HoldingRegisters
так чтобы они принимали self
вместо &mut self
и делать имплементацию для &'a mut T
.
Сделал такой вариант
pub trait HoldingRegisters {
fn get<A: Into<u16>>(&mut self, addr: A) -> Result<u16>;
fn gets<A: Into<u16>, D: From<u16>>(&mut self, start_addr: A, buff: &mut [D]) -> Result<()>;
fn set<A: Into<u16>, D: Into<u16>>(&mut self, addr: A, data: D) -> Result<()>;
fn sets<A: Into<u16>, D: Into<u16> + Copy>(&mut self, start_addr: A, buff: &[D]) -> Result<()>;
}
pub trait RawHoldingRegisters<'a> {
type Data: RawData + 'a;
fn put<A: Into<u16>>(&mut self, start_addr: A, registers: u16, bytes: u8) -> Self::Data;
fn pop<A: Into<u16>>(&mut self, start_addr: A, registers: u16) -> Self::Data;
}
pub trait RawData {
fn query(&mut self) -> Result<&mut Self>;
fn as_slice(&self) -> &[u8];
fn as_mut_slice(&mut self) -> &mut [u8];
}
impl<'a, T> HoldingRegisters for T where T: RawHoldingRegisters<'a> {
fn get<A: Into<u16>>(&mut self, addr: A) -> Result<u16> {
Ok(BigEndian::read_u16(self.pop(addr, 1).query()?.as_slice()))
}
fn gets<A: Into<u16>, D: From<u16>>(&mut self, _start_addr: A, _buff: &mut [D]) -> Result<()> {
Ok(())
}
fn set<A: Into<u16>, D: Into<u16>>(&mut self, _addr: A, _data: D) -> Result<()> {
Ok(())
}
fn sets<A: Into<u16>, D: Into<u16> + Copy>(&mut self, _start_addr: A, _buff: &[D]) -> Result<()> {
Ok(())
}
}
но теперь проблема с реализацией:
struct Device {
buffer: [u8; 16],
}
struct Data<'a> {
own: &'a mut Device,
}
impl<'a> RawData for Data<'a> {
fn query(&mut self) -> Result<&mut Self> {
Ok(self)
}
fn as_slice(&self) -> &[u8] {
&self.own.buffer[..]
}
fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.own.buffer[..]
}
}
impl<'a> RawHoldingRegisters<'a> for Device {
type Data = Data<'a>;
fn put<A: Into<u16>>(&mut self, start_addr: A, registers: u16, bytes: u8) -> Self::Data {
Data{own: self}
}
fn pop<A: Into<u16>>(&mut self, start_addr: A, registers: u16) -> Self::Data {
Data{own: self}
}
}
ошибка:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:69:9
|
69 | Data{own: self}
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 68:5...
--> src/lib.rs:68:5
|
68 | / fn put<A: Into<u16>>(&mut self, start_addr: A, registers: u16, bytes: u8) -> Self::Data {
69 | | Data{own: self}
70 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:69:19
|
69 | Data{own: self}
| ^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 66:6...
--> src/lib.rs:66:6
|
66 | impl<'a> RawHoldingRegisters<'a> for Device {
| ^^
= note: ...so that the types are compatible:
expected RawHoldingRegisters<'a>
found RawHoldingRegisters<'_>
код целиком - https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=76f9690f35bb0b324c26969f5ba5cca4
Два варианта:
Пока не реализуют Generic Associated Types придется обходится подобными костылями.
Нашел еще одно решение, но оно совсем уже хитро вывернутое.
Суть в том что мы убираем ассоциированный тип в типаже RawHoldingRegisters
, а возвращаемое значение задаем через ассоциированный тип нового типажа DeviceObject<'_>
. Это позволяет избежать засорения временами жизни с помощью Higher Ranked Trait Bound:
pub trait RawHoldingRegisters: for<'a> DeviceObject<'a> { ... }
Вот статья в которой описан похожий метод:
Solving the Generalized Streaming Iterator Problem without GATs
отличная статья,
спасибо за помощь!
Вопрос по специализации:
в коде уже было impl HoldingRegisters for Device
, и когда появилась impl RawHoldingRegisters for Device
компилятор выдал ошибку:
error[E0119]: conflicting implementations of trait `HoldingRegisters` for type `Device`:
--> src/lib.rs:85:1
|
26 | impl<T> HoldingRegisters for T where T: RawHoldingRegisters {
| ----------------------------------------------------------- first implementation here
...
85 | impl HoldingRegisters for Device {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Device`
вроде бы ни чего не нарушено, поскольку HoldingRegisters
был реализован для T
:
impl<T> HoldingRegisters for T where T: RawHoldingRegisters
,
но не был реализован для конкретного Device
,
или специализация работает не до конца полностью?
А с каких пор специализация вообще работает? ) Её же как небыло, так и нет.
А это разве не то:
Now, this works quite well when specializing a blanket impl with an impl for a concrete type:
impl<T> SomeTrait for T { /* default fns */ }
impl SomeTrait for SomeType { /* specialized fns */ }
Неа, это не то. В этой серии статей идет обсуждение о решении проблем реализации специализации и об эргономике предлагаемых решений. До, собственно, самой реалиизации еще дело не дошло: https://github.com/rust-lang/rust/issues/31844