Returning a pointer to a boxed value from a collection in Rust - pointers

I have a collection of boxed object:
objects : Vec<Box<MyObject>>
I have a function that needs to return a *mut MyObject, and it pretty much look like this.
for object in self.objects.iter()
{
if object.name == new_object_name
{
return &mut *object;
}
}
return std::ptr::null_mut();
But I am getting an error during compilation on return line:
expected struct `MyObject`, found struct `Box`

You need to dereference twice, as object is &Box<MyObject>, and use iter_mut() because you want a mutable reference:
for object in self.objects.iter_mut() {
if object.name == new_object_name {
return &mut **object;
}
}
return std::ptr::null_mut();

Related

Rust: Joining and iterating over futures' results

I have some code that iterates over objects and uses an async method on each of them sequentially before doing something with the results. I'd like to change it so that the async method calls are joined into a single future before being executed. The important bit below is in HolderStruct::add_squares. My current code looks like this:
use anyhow::Result;
struct AsyncMethodStruct {
value: u64
}
impl AsyncMethodStruct {
fn new(value: u64) -> Self {
AsyncMethodStruct {
value
}
}
async fn get_square(&self) -> Result<u64> {
Ok(self.value * self.value)
}
}
struct HolderStruct {
async_structs: Vec<AsyncMethodStruct>
}
impl HolderStruct {
fn new(async_structs: Vec<AsyncMethodStruct>) -> Self {
HolderStruct {
async_structs
}
}
async fn add_squares(&self) -> Result<u64> {
let mut squares = Vec::with_capacity(self.async_structs.len());
for async_struct in self.async_structs.iter() {
squares.push(async_struct.get_square().await?);
}
let mut sum = 0;
for square in squares.iter() {
sum += square;
}
return Ok(sum);
}
}
I'd like to change HolderStruct::add_squares to something like this:
use futures::future::join_all;
// [...]
impl HolderStruct {
async fn add_squares(&self) -> Result<u64> {
let mut square_futures = Vec::with_capacity(self.async_structs.len());
for async_struct in self.async_structs.iter() {
square_futures.push(async_struct.get_square());
}
let square_results = join_all(square_futures).await;
let mut sum = 0;
for square_result in square_results.iter() {
sum += square_result?;
}
return Ok(sum);
}
}
However, the compiler gives me this error using the above:
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> src/main.rs:46:20
|
46 | sum += square_result?;
| ^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `&std::result::Result<u64, anyhow::Error>`
|
= help: the trait `std::ops::Try` is not implemented for `&std::result::Result<u64, anyhow::Error>`
= note: required by `std::ops::Try::into_result`
How would I change the code to not have this error?
for square_result in square_results.iter()
Lose the iter() call here.
for square_result in square_results
You seem to be under impression that calling iter() is mandatory to iterate over a collection. Actually, anything that implements IntoIterator can be used in a for loop.
Calling iter() on a Vec<T> derefs to slice (&[T]) and yields an iterator over references to the vectors elements. The ? operator tries to take the value out of the Result, but that is only possible if you own the Result rather than just have a reference to it.
However, if you simply use a vector itself in a for statement, it will use the IntoIterator implementation for Vec<T> which will yield items of type T rather than &T.
square_results.into_iter() does the same thing, albeit more verbosely. It is mostly useful when using iterators in a functional style, a la vector.into_iter().map(|x| x + 1).collect().

How to use map as data carrier in Go?

I am unsure about correct terms, but how do I use this:
type MyType map[string]string
as "data carrier" (or object in OOP)?
This does not work:
func NewMyType() *MyType {
return make(MyType)
}
I do want to use pointer but apparently this does not work, the compiler expects reference on return.
The builtin make() function creates a non-pointer value of your MyType map type, yet the return type is a pointer. That's what the error message tells if you try to compile it:
cannot use make(MyType) (type MyType) as type *MyType in return argument
If you return a pointer to the value, it works:
type MyType map[string]string
func NewMyType() *MyType {
m := make(MyType)
return &m
}
If you would want to use a single line for it, you could use a composite literal:
func NewMyType() *MyType {
return &MyType{}
}
But maps (map values) are already implement as pointers in the background, so this is redundant and unnecessary. Just return the map-value as-is:
type MyType map[string]string
func NewMyType() MyType {
return make(MyType)
}
Or with a composite literal:
func NewMyType() MyType {
return MyType{}
}
Although "constructors" for such simple types (simple creation) are not necessary, unless you want to do other things before returning it (e.g. specify its initial capacity or fill it with initial values).

Can I return a struct which uses PhantomData from a trait implementation to add a lifetime to a raw pointer without polluting the interface?

In this question someone commented that you could use PhantomData to add a lifetime bound to a raw pointer inside a struct. I thought I'd try doing this on an existing piece of code I've been working on.
Here's our (minimised) starting point. This compiles (playground):
extern crate libc;
use libc::{c_void, free, malloc};
trait Trace {}
struct MyTrace {
#[allow(dead_code)]
buf: *mut c_void,
}
impl MyTrace {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
}
}
}
impl Trace for MyTrace {}
impl Drop for MyTrace {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer {
trace: Option<MyTrace>,
}
impl MyTracer {
fn new() -> Self {
Self { trace: None }
}
}
impl Tracer for MyTracer {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
I think that the problem with the above code is that I could in theory move the buf pointer out of a MyTrace and use if after the struct has died. In this case the underlying buffer will have been freed due to the Drop implementation.
By using a PhantomData we can ensure that only references to buf can be obtained, and that the lifetimes of those references are bound to the instances of MyTrace from whence they came.
We can proceed like this (playground):
extern crate libc;
use libc::{c_void, free, malloc};
use std::marker::PhantomData;
trait Trace {}
struct MyTrace<'b> {
#[allow(dead_code)]
buf: *mut c_void,
_phantom: PhantomData<&'b c_void>,
}
impl<'b> MyTrace<'b> {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
_phantom: PhantomData,
}
}
}
impl<'b> Trace for MyTrace<'b> {}
impl<'b> Drop for MyTrace<'b> {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer<'b> {
trace: Option<MyTrace<'b>>,
}
impl<'b> MyTracer<'b> {
fn new() -> Self {
Self { trace: None }
}
}
impl<'b> Tracer for MyTracer<'b> {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
But this will give the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:53:36
|
53 | Box::new(self.trace.take().unwrap())
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'b as defined on the impl at 46:1...
--> src/main.rs:46:1
|
46 | impl<'b> Tracer for MyTracer<'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::option::Option<MyTrace<'_>>
found std::option::Option<MyTrace<'b>>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<Trace + 'static>
found std::boxed::Box<Trace>
I have three sub-questions:
Did I understand the motivation for PhantomData in this scenario correctly?
Where is 'static coming from in the error message?
Can this be made to work without changing the interface of stop? Specifically, without adding a lifetime to the return type?
I'm going to ignore your direct question because I believe you arrived at it after misunderstanding several initial steps.
I could in theory move the buf pointer out of a MyTrace and use if after the struct has died
Copy the pointer, not move it, but yes.
By using a PhantomData we can ensure that only references to buf can be obtained
This is not true. It is still equally easy to get a copy of the raw pointer and misuse it even when you add a PhantomData.
Did I understand the motivation for PhantomData in this scenario correctly?
No. PhantomData is used when you want to act like you have a value of some type without actually having it. Pretending to have a reference to something is only useful when there is something to have a reference to. There's no such value to reference in your example.
The Rust docs say something about raw pointers and PhantomData, but I perhaps got it wrong
That example actually shows my point well. The Slice type is intended to behave as if it has a reference to the Vec that it's borrowed from:
fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T>
Since this Slice type doesn't actually have a reference, it needs a PhantomData to act like it has a reference. Note that the lifetime 'a isn't just made up out of whole cloth — it's related to an existing value (the Vec). It would cause memory unsafety for the Slice to exist after the Vec has moved, thus it makes sense to include a lifetime of the Vec.
why the commenter in the other question suggested I use PhantomData to improve the type safety of my raw pointer
You can use PhantomData to improve the safety of raw pointers that act as references, but yours doesn't have some existing Rust value to reference. You can also use it for correctness if your pointer owns some value behind the reference, which yours seemingly does. However, since it's a c_void, it's not really useful. You'd usually see it as PhantomData<MyOwnedType>.
Where is 'static coming from in the error message?
Why is adding a lifetime to a trait with the plus operator (Iterator<Item = &Foo> + 'a) needed?

How to initialize an empty pointer by reflect

This is a very straight forward question.
How do you implement Initialize() below with reflect?
Or is this possible?
func Initialize(v interface{}) {
// ... some reflection code
}
type MyType struct {
Name string
}
func main() {
var val *MyType
// val is nil before initialize
Initialize(val)
// val is now &MyType{Name: ""}
// ...
}
```
Here's how to do it:
func Initialize(v interface{}) {
rv := reflect.ValueOf(v).Elem()
rv.Set(reflect.New(rv.Type().Elem()))
}
This function must be called with a pointer to the value to set:
Initialize(&val)
playground example
The code in this answer panics if the argument type is not a pointer to a pointer. Depending on your use, you might want to check the reflect value kind before calling Elem().

Go linked list pointer assignment from non-pointer struct element

https://github.com/golang/go/blob/master/src/container/list/list.go#L49
I am having hard time why I am getting cannot assign to pointer error in Go.
Here's the code that works: http://play.golang.org/p/P9FjK8A-32 which is same as Go's original container/list code
type List struct {
root Element
len int
}
type Element struct {
next, prev *Element
list *List
Value interface{}
}
The original code has root as a value and reference it everytime it needs to be in pointer type but why not at first place define root as a pointer?
type List struct {
root *Element
len int
}
type Element struct {
next, prev *Element
list *List
Value interface{}
}
This give me an error: http://play.golang.org/p/1gCAR_rcx1 -> invalid memory address or nil pointer dereference
Why am I getting this error?
Why does Go define root as a non-pointer value when it defines next, and prev as pointers?
Thanks
A pointer is nil by default and needs to be initialized.
This:
// Init initializes or clears list l.
func (l *List) Init() *List {
l.root.next = l.root
l.root.prev = l.root
l.len = 0
return l
}
should become this:
// Init initializes or clears list l.
func (l *List) Init() *List {
l.root = new(Element) // necessary to avoid dereferencing a nil pointer
l.root.next = l.root
l.root.prev = l.root
l.len = 0
return l
}
Demo at http://play.golang.org/p/EYSscTMYnn
In the case of the standard library, it is not necessary to have root be a pointer, however, for prev and next it is necessary, otherwise the struct definition would be recursive, which is not allowed, because it would in theory cause a struct of infinite size...

Resources