rust


Unused type parameters when binding a generic type to a trait that takes lifetime


use std::collections::HashMap;
use std::hash::Hash;
struct Watchable<'a, K, V, W: Watcher<'a, K, V>> {
data: HashMap<K, V>,
watchers: Vec<W>,
}
trait Watcher<'a, K, V> {
fn before_new(&mut self, key: &'a K, value: &'a V);
}
struct IndexWatcher<'a, I: 'a, V: 'a> {
data: HashMap<&'a I, &'a V>,
indexer: fn(&V) -> &I,
}
impl<'a, K, V, I> Watcher<'a, K, V> for IndexWatcher<'a, I, V>
where I: Eq + Hash
{
fn before_new(&mut self, key: &'a K, value: &'a V) {
let index = (self.indexer)(value);
self.data.insert(index, value);
}
}
error[E0392]: parameter `'a` is never used
--> src/main.rs:4:18
|
4 | struct Watchable<'a, K, V, W: Watcher<'a, K, V>> {
| ^^ unused type parameter
|
= help: consider removing `'a` or using a marker such as `std::marker::PhantomData`
Is there any way to remove some lifetime annotation? It seems everything has the same lifetime a.
At first, I didn't put any specific lifetime:
struct IndexWatcher<I, V> {
data: HashMap<&I, &V>,
indexer: fn(&V) -> &I,
}
The compiler complained about lifetimes, so I added it:
struct IndexWatcher<'a, I: 'a, V: 'a> {
data: HashMap<&'a I, &'a V>,
indexer: fn(&V) -> &I,
}
When I tried to implement the trait without lifetimes:
trait Watcher<K, V> {
fn before_new(&mut self, key: &K, value: &V);
}
impl<'a, K, V, I> Watcher<K, V> for IndexWatcher<'a, I, V>
where I: Eq + Hash
{
fn before_new(&mut self, key: &K, value: &V) {
let index = (self.indexer)(value);
self.data.insert(index, value);
}
}
I got the error:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> <anon>:18:33
|
18 | self.data.insert(index, value);
| ^^^^^
|
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> <anon>:17:21
|
17 | let index = (self.indexer)(value);
| ^^^^^^^^^^^^^^^^^^^^^
|
Hence my final version with lifetimes everywhere.
Ideally, I would like to use the trait in Watchable like the following:
impl<K, V, W: Watcher<K, V>> Watchable<K, V, W>
where K: Eq + Hash {
fn insert(&mut self, k: K, v: V) -> Option<V> {
match self.data.entry(k) {
Occupied(mut occupied) => {
{
let k = occupied.key();
let old = occupied.get();
for watcher in &mut self.watchers {
watcher.before_change(k, &v, old);
}
}
let old = occupied.insert(v);
Some(old)
},
Vacant(vacant) => {
{
let k = vacant.key();
for watcher in &mut self.watchers {
watcher.before_new(k, &v);
}
}
vacant.insert(v);
None
}
}
}
}
trait Watcher<K, V> {
fn before_new(&mut self, key: &K, value: &V);
fn before_change(&mut self, key: &K, value: &V, old: &V);
}
You can get rid of the error by using a higher-rank trait bound instead of a lifetime parameter:
struct Watchable<K, V, W: for<'a> Watcher<'a, K, V>> {
data: HashMap<K, V>,
watchers: Vec<W>,
}
That doesn't solve your problem though. IndexWatcher will not satisfy the bound for<'a> Watcher<'a, K, V> because a IndexWatcher<'a, I, V> only implements Watcher<'a, K, V> for one specific lifetime, not for all possible lifetimes.
Fundamentally, the problem is that you're trying to put a value and a reference to that value in the same struct (indirectly). That is, your idea is that the watchers are expected to borrow data from the Watchable, but the Watchable also owns the watchers. Please take the time to read this question and Shepmaster's answer to understand why that idea is not going to work.
In particular, be aware that inserting an entry in or removing an entry from the Watchable's HashMap might invalidate the references in any of the watchers due to HashMap needing to reallocate storage, which may cause the address of the keys and values to change.
What I would do instead is wrap the keys and values in an Rc (or an Arc if you want to share a Watchable across threads). Getting a shared index value out of a Rc<V> might be problematic though. Consider changing your index function to fn(&V) -> I, and have the index functions return clones (they can be clones of an Rc if cloning the index value is too expensive) or handles.

Related Links

Literal out of range warning when iterating over all values of u8
How to write a trait that has a method returning a reference and implement it correctly?
Mismatched types when displaying a matrix with a for loop
How to have a struct field with the same mutability as the parent struct?
`if` condition remains borrowed in body [duplicate]
“parameter `'a` is never used” error when 'a is used in type parameter bound
Linking Rust application with a dynamic library not in the runtime linker search path
Can't access environment variable in Rust
How to wrap a call to a FFI function that uses VarArgs in Rust?
Change terminal cursor position in Rust
Is it better to destructure a value to access attributes or use their names?
How is every dynamically checked aspect of Rust implemented?
Referring to matched value in Rust
Reference to unwrapped property fails: use of partially moved value: `self`
Read one level of directory structure
How does one operate over a subset of a vector?

Categories

HOME
android-espresso
mod-rewrite
activex
activemq
nsview
fogbugz
sharepoint-online
siesta
sap-fiori
bootstrap-switch
jpa-2.0
orange-api
reselect
http-authentication
spam
infrared
pfobject
kaggle
liferay-6.2
cell
software-packaging
opentext
environment
raima
msdeploy
boolean-logic
dnsmasq
audit
d3.js-v4
series
plantuml
lxml
cmis
busboy
xll
suds
notesview
viewmodel
scala-breeze
nusoap
karabiner
skip-lists
android-sharing
word-2007
patternlab.io
mobile-angular-ui
glimpse
polymaps
predicates
msxml
nitrousio
ipywidgets
libharu
mathjs
openquery
qtcpsocket
bbc-micro
processor
gravatar
as3-api
android-mapview
embeddedwebserver
angular-amd
kotlin-android-extensions
azure-xplat-cli
subview
datagridcomboboxcolumn
global-scope
lmax
oracle-adf-mobile
box2dweb
neo4jphp
incognito-mode
flipboard
django-sites
django-settings
mft
sensormanager
sql-view
jquery-lazyload
html-frames
significant-digits
sfinae
uipangesturerecognizer
flymake
autosize
eaccelerator
odac
tabbarcontroller
zend-test
firephp
xap
twitter-feed
suggestbox
remote-working
jvm-bytecode
synthesizer

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App