Reverse iterating over a &vec versus vec.iter() - iterator

This works because Iterator implements rev() where self is a DoubleEndedIterator:
let vec: Vec<i32> = Vec::new();
for x in vec.iter().rev() {
//Do stuff
}
However, if I change vec.iter().rev() to &vec.rev() it won't compile because:
no method named `rev` found for type `std::vec::Vec<i32>` in the current scope
Furthermore:
the method `rev` exists but the following trait bounds were not satisfied: `std::vec::Vec<i32> : std::iter::Iterator`, `[i32] : std::iter::Iterator`
But doesn't a for loop implicitly call IntoIterator? Is &vec or vec.iter() considered idiomatic Rust?

If you're just looping over the Vec, then &vec is idiomatic. This works because &Vec<T> implements IntoIterator, which is what the for loop uses.
However if you want to call Iterator methods such as rev, filter, etc., you need an actual Iterator (since Vec doesn't implement Iterator, only IntoIterator).
So this:
for x in &vec.rev() {
...
}
is equivalent to:
for x in (&vec.rev()).into_iter() {
...
}
i.e. there's no chance to use IntoIterator before trying to call Iterator methods.

This is just basic precedence of the & operator. In the first case, each method is called in turn:
vec.iter().rev()
(vec.iter()).rev() // same
In the second case, the & binds after all the methods:
&vec.rev()
&(vec.rev()) // same
Generally, use &vec when you can, but when you need to use iterator adapter methods, use iter or into_iter.

Related

Indirect initialization of memory via UnsafeMutablePointer types

I encountered an unfamiliar pattern of initialization from Objective-C that I'm struggling to replicate in Swift.
Objective-C
In the example code, they defined a C struct such as this (abbreviated, original here):
struct AQPlayerState {
AudioFileID mAudioFile;
}
Here's an example that uses AQPlayerState:
AQPlayerState aqData; // 1
OSStattus result =
AudioFileOpenURL(
audioFileURL,
fsRdPerm,
0,
&aqData.mAudioFile // 2
);
The key takeaway from above is that aqData currently has uninitialized properties, and AudioFileOpenURL is initializing aqData.mAudioFile on it's behalf.
Swift
I'm trying to replicate this behaviour in Swift. Here's what I've tried so far:
Models:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
class Foo {
var person: Person?
}
My idea was to replicate the Objective-C code by passing a reference of Foo.person into a function that would instantiate it on it's behalf.
Initialization Function:
func initializeWithBob(_ ptr: UnsafeMutablePointer<Person?>) {
ptr.pointee = Person(name: "Bob")
}
initializeWithBob takes a pointer to an address for a Person? type and initializes it with a Person(name: "Bob") object.
Here's my test code:
let foo = Foo()
let ptr = UnsafeMutablePointer<Person?>.allocate(capacity: 1)
ptr.initialize(to: foo.person)
defer {
ptr.deinitialize()
ptr.deallocate(capacity: 1)
}
initializeWithBob(ptr)
print(foo.person) // outputs nil
initializeWithBob failed to "install" an instance of type Person in my Foo instance. I presume some of my assumptions are wrong. Looking for help in correcting my assumptions and understanding of this situation.
Thanks in advance!
You can achieve what you are looking for via withUnsafeMutablePointer(to:_:) like so:
let foo = Foo()
withUnsafeMutablePointer(to: &foo.person) { (ptr) -> Void in
initializeWithBob(ptr)
}
print(foo.person!.name) // outputs Bob
However, I wouldn't recommend this approach. IMHO it makes more sense to wrap the APIs you are working with in a C function that you can make 'nice' to call from Swift. The problem with your current approach is that this type of Swift is hard to read for Swift developers and also hard to read for Audio Toolbox developers.
#kelvinlau Is this what you were thinking of trying to achieve?
func initializeWithBob(_ ptr: UnsafeMutablePointer<Foo>) {
ptr.pointee.person = Person(name: "Bob")
}
let foo = Foo()
let ptr = UnsafeMutablePointer<Foo>.allocate(capacity: 1)
ptr.initialize(to: foo)
initializeWithBob(ptr)
print(foo.person?.name ?? "nil")
ptr.deinitialize()
ptr.deallocate(capacity: 1)
print(foo.person?.name ?? "nil")
The code pattern you have in Objective-C is for out parameters, that is parameters which return a value, or in out parameters, that is parameters which both pass a value in and return one. Objective-C does not directly support these so pointers are used to produce the semantics.
Swift has in out parameters indicated by the keyword inout in the function declaration. Within the function an assignment to an inout parameters effectively assigns a value to the variable that was passed as the argument. At the function call site the variable must be prefixed by & to indicate it is the variable itself and not its value which is effectively being passed.
Keeping your Person and Foo as is your function becomes:
func initializeWithBob(_ ptr: inout Person?)
{
ptr = Person(name: "Bob")
}
and it may be used, for example, like:
var example = Foo()
initializeWithBob(&example.person)
Using inout in Swift is better than trying to build the same semantics using pointers.
HTH
Note: You can skip this unless you are curious
"Effectively" was used a few times above. Typically out parameters are implemented by the parameter passing method call-by-result, while in out use call-by-value-result. Using either of these methods the returned value is only assigned to the passed variable at the point the function returns.
Another parameter passing method is call-by-reference, which is similar to call-by-value-result except that each and every assignment to the parameter within the function is immediately made to passed variable. This means changes to the passed variable may be visible before the function returns.
Swift by design does not specify whether its inout uses call-by-value-result or call-by-reference. So rather than specify the exact semantics in the answer "effectively" is used.

Is there a Rust equivalent to `dynamic` in C#?

Can the following C# code be translated to Rust?
dynamic x = 109;
x = "Hi";
I'm asking for a general dynamic type to allow creating an array of dynamic values. For example:
var l = new dynamic[2];
l[0] = 102;
l[1] = "Hi";
One option is to use a vector of Any (link to beta because the stable docs is not showing the methods defined for Any, but they are stable):
use std::any::Any;
fn main() {
let mut v: Vec<Box<Any>> = vec![];
v.push(Box::new(102usize));
v.push(Box::new("Hi"));
for item in &v {
// to do an operation, it is necessary to downcast to
// a concrete type
if let Some(x) = item.downcast_ref::<usize>() {
println!("num = {:?}", x)
}
}
}
Note that, contrary to dynamic in C#, that is assumed to support any operation, a value of type Any (Box<Any>) only support the operations defined in Any (Box<Any> and Any). A downcast is necessary to call any method of the concrete type.
I think that it is not possible to have a type like dynamic of C# in Rust. To support calling any method on a dynamic value, it is necessary to have (complete) runtime reflection support, and Rust does not provide it.
If you know the methods that will be called, then the best option is to define a trait and use Box<Trait> (Any is not necessary in this case).
Not directly. You can just create a new binding for x:
fn main() {
let x = 109;
let x = "Hi";
}
Depending on your use case, you might be able to use a generic bounded by a trait or a trait object to achieve similar goals:
use std::fmt::Display;
fn main() {
let mut x: Box<Display> = Box::new(109);
x = Box::new("Hi");
}
However, the C# docs state:
At compile time, an element that is typed as dynamic is assumed to support any operation.
This is not true for a trait object; a trait object only can be used for the explicit methods in the trait. I have not found this to be a significant hurdle in the code I have written. Generally, there's a fixed number of methods that I want to call so it's possible to map those to a trait. In other cases, I can provide a generic type to allow the user to specify a type that fits their case.

How to create an empty iterator for a certain collection type (list/set/map) in Rust?

I want to write a method which returns an iterator for a collection (e.g.
LinkedList). But in some cases there's no suitable collection to return an
iterator for. In such cases I'd like to return an "empty" iterator which
iterates over no elements. But I couldn't find any associated function to
construct a linked_list::Iter in the documentation.
Consider the following example:
use std::collections::HashMap;
use std::collections::LinkedList;
use std::collections::linked_list;
pub struct Graph {
nodes: HashMap<usize, LinkedList<usize>>,
}
impl Graph {
pub fn adjacent_nodes(&self, node: usize) -> linked_list::Iter<usize> {
match self.nodes.get(&node) {
Some(x) => x.iter(),
_ => linked_list::Iter::<usize>::new()
}
}
}
I'd like to return an iterator over adjacent nodes from the adjacent_nodes
method. But when asked for neighbours of a non-existing node, the method should
return an iterator over nothing, obviously. But how could I create it? The code
I gave doesn't compile actually:
src/graph.rs:13:18: 13:49 error: no associated item named `new` found for type
`collections::linked_list::Iter<'_, usize>` in the current scope
src/graph.rs:13 _ => linked_list::Iter::<usize>::new()
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I guess, I could solve the problem with boxed::Box but it is clearly a
suboptimal solution because of unnecessary heap allocation that I try to avoid.
So, my question is: Is it possible in Rust to create an iterator-over-nothing of
specific type?
You cannot do it, not with by-reference iterators, because they are always tied to a concrete collection instance.
What you can do is to return boxed iterator as a trait object:
pub fn adjacent_nodes<'a>(&'a self, node: usize) -> Box<Iterator<Item=usize>+'a> {
match self.nodes.get(&node) {
Some(x) => Box::new(x.iter()),
_ => Box::new(::std::iter::empty())
}
}
std::iter::empty() returns an empty iterator, but of course its type is different from those of collection iterators, so you have to use a trait object. I also had to add a lifetime parameter because the iterator returned by iter() is tied to self.nodes, and you need to explain it to the compiler.

Is there an Iterator-like trait which returns references that must fall out of scope before the next access?

This would make it possible to safely iterate over the same element twice, or to hold some state for the global thing being iterated over in the item type.
Something like:
trait IterShort<Iter>
where Self: Borrow<Iter>,
{
type Item;
fn next(self) -> Option<Self::Item>;
}
then an implementation could look like:
impl<'a, MyIter> IterShort<MyIter> for &'a mut MyIter {
type Item = &'a mut MyItem;
fn next(self) -> Option<Self::Item> {
// ...
}
}
I realize I could write my own (I just did), but I'd like one that works with the for-loop notation. Is that possible?
The std::iter::Iterator trait can not do this, but you can write a different trait:
trait StreamingIterator {
type Item;
fn next<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
}
Note that the return value of next borrows the iterator itself, whereas in Vec::iter for example it only borrows the vector.
The downside is that &mut is hard-coded. Making it generic would require higher-kinded types (so that StreamingIterator::Item could itself be generic over a lifetime parameter).
Alexis Beingessner gave a talk about this and more titled Who Owns This Stream of Data? at RustCamp.
As to for loops, they’re really tied to std::iter::IntoIterator which is tied to std::iter::Iterator. You’d just have to implement both.
The standard iterators can't do this as far as I can see. The very definition of an iterator is that the outside has control over the elements while the inside has control over what produces the elements.
From what I understand of what you are trying to do, I'd flip the concept around and instead of returning elements from an iterator to a surrounding environment, pass the environment to the iterator. That is, you create a struct with a constructor function that accepts a closure and implements the iterator trait. On each call to next, the passed-in closure is called with the next element and the return value of that closure or modifications thereof are returned as the current element. That way, next can handle the lifetime of whatever would otherwise be returned to the surrounding environment.

How do I apply an explicit lifetime bound to a returned trait?

Returning an iterator from a function in Rust is an exercise of Sisyphean dimensions, but I am told it's possible to return one as a trait without quite so much pain. Unfortunately, it isn't working: apparently, I need an explicit lifetime bound? Which is apparently not the same thing as adding a lifetime parameter. Which means I have no idea how to do that.
Here's my (tiny, test) code:
fn main() {
let args = get_args();
for arg in args {
println!("{}", arg);
}
}
fn get_args() -> Iterator {
std::env::args().filter_map(|arg| arg.into_string().ok())
}
What is the appropriate way to make this actually work?
Edit: rust version rustc 1.0.0-nightly (00df3251f 2015-02-08 23:24:33 +0000)
You can't return a bare Iterator from a function, because it is a trait, thus not a sized type.
In your situation, you'll need to put the iterator object inside a box, in order to make it into a sized object that can be returned from the function.
To do so, you can change your code like this:
fn get_args() -> Box<Iterator<Item=String> + 'static> {
Box::new(std::env::args().filter_map(|arg| arg.into_string().ok()))
}
Here I've added a lifetime specifier 'static for the trait object, meaning that it is completely self-owned (a function taking no arguments will almost always return something valid for the 'static lifetime in this sense).
You also need the <Item=String> part to explicit the type of data yielded by your iterator. In this case: Strings.
In this specific case you can manage to return a concrete type from your get_args, like so:
fn get_args() -> FilterMap<Args, fn(OsString) -> Option<String>> {
fn arg_into_string(arg: OsString) -> Option<String> { arg.into_string().ok() }
args().filter_map(arg_into_string as fn(OsString) -> Option<String>)
}
basically this applies to all the cases where the closure you use in the iterator adapter (in your case filter_map) is not really a closure, in that it does not capture any environment, and it can be modeled by a plain old function.
In general, if you do need to return a type that does contain a closure, you will indeed need to box it and return a trait object. In your case:
fn get_args() -> Box<Iterator<Item=String> + 'static> {
Box::new(std::env::args().filter_map(|arg| arg.into_string().ok()))
}