Hi,
I'm relatively new to rust and I'm struggling a bit with types an ownership. For back ground I am using rustler to write a nif for Elixir to access the rust aerospike library. (Yeah, I'm in way over my head.) I have the nif mostly working but I'm not sure about one part. The relavant code is:
let mut bins: Vec<&Bin> = Vec::new();
for (k, v) in values {
let s: String = try!(v.decode());
let bin: Bin<'a> = as_bin!(k.decode()?, s);
bins.push(&bin)
}
let res = match client.client.put(&WritePolicy::default(), &key, &bins) {
...
I'm making a vector of references to Bins to pass to put()
. The issue is that the bin is dropped at the end of the for loop so bins.push(&bin)
is an error.
How do I fix this?
You probably want bins
to own the Bin
values, i.e.:
let mut bins: Vec<Bin> = Vec::new();
...
let bin = as_bin!(k.decode()?, s);
bins.push(bin);
It's a bit hard to say without seeing the definition of the involved types/functions.
Also you can use the iterators and collect it into the vector. That way you don't need a mutable vector.
Sorry, I should have supplied the definition of put(). It looks like:
fn put(&self, policy: &WritePolicy, key: &Key, bins: &[&Bin]) -> Result<()>
The difficulty is making the &[&Bin]]
value.
Is put()
in your control?
No, put() is part of the aerospike rust library.
That's too bad - there might've been a way to make it generic over a slice of either owned or borrowed Bin
s. But ok ...
So the simple approach, then, would be to build a second Vec of references:
let mut bins: Vec<Bin> = Vec::new();
...
let bins = bins.iter().collect::<Vec<_>>();
put(..., &bins);
Kind of unfortunate to have to do this though.
or
let bins: Vec<Bin> = bins.iter().collect();
What's the initial bins
in your example? His example has a for loop over some tuples, but he has fallible operators inside the body of the loop that do a function exit if an Err is seen. That won't work with iterator combinators without more code refactoring.
But anyway, that stylistic thing is sort of secondary to the main question, I think
.
let bins = bins.iter().collect::<Vec<_>>();
worked.
iex(1)> {:ok, client} = Aerospike.connect("172.28.128.3:3000")
{:ok, #Reference<0.347712306.2185625606.33170>}
iex(2)> res = Aerospike.put(client, "test", "test", "test", %{"id" => "1234", "uuid" => "abcd"})
{:ok, "ok"}
iex(3)> {:ok, res} = Aerospike.get(client, "test", "test", "test")
{:ok, %{"id" => "1234", "int" => 999, "uuid" => "abcd"}}
Thanks everyone!
Yeah, I need to read up a bit more on ownership.
If you want, ask aerospike lib maintainers to change put() to:
fn put<A: AsRef<Bin>>(..., bins: &[A]) ...
// or if a slice isn’t necessary and iterator works
fn put<I: IntoIterator<Item=A>, A: AsRef<Bin>>(iter: I) ...
Then you won’t need that second Vec of references.