Rust - create filter predicate as function - rust

I want to create a function which returns a predicate.
I have an vector and I want to filter based on character a specific character. My code:
let n = 0; // Irrelevant. This will change
co2 = co2
.into_iter()
.filter(|&binary| binary.chars().collect::<Vec<char>>().get(n).unwrap() == &'1')
.collect();
I have a couple of characters I want to match. My intention was to create a function like this:
fn create_predicate(character: char, n: usize) -> impl FnMut(&str) {
move |x: &str| {
return x.chars().collect::<Vec<char>>().get(n).unwrap() == &character;
}
}
co2 = co2.filter(create_predicate('q', n));
This wont work, but I would like to make it look something like that
So I want to have a function that creates a predicate which I can use in my filter. How can I do that?

Hard to give a complete answer without a full minimal reproducible example, but you can get close with two changes to your code:
The predicate must return bool if you want to use it in filter.
Possibly, the predicate must take &&str.
Working example:
fn create_predicate(character: char, n: usize) -> impl FnMut(&&str) -> bool {
move |x: &&str| {
return x.chars().collect::<Vec<char>>().get(n).unwrap() == &character;
}
}
fn main() {
let co2 = [ "azerty", "foo", "bar" ];
let co2 = co2.iter().copied().filter(create_predicate('q', 1));
}
Playground

Related

Iterating over a vector gives me a different value than what is inside the vector Rust

I have been using Petgraph recently to make simple graphs with Structs for nodes and custom edges, but I have come across a problem which I am unsure if it comes from the library or Rust.
I have a graph, in which I have multiple nodes, each nodes have a name. I then put all of the index of the node (with type NodeIndex) in a vector, since Petgraph doesn't have a function to give all the nodes from a graph. I want to then create a function that given a string, it returns the index of the node that matches the name.
My problem is that somehow the type in the vector containing the nodes seems to change. I store it as NodeIndex yet the types somehow change by themselves to u32 without me changing anything. Since it changes automatically, I can't pass the values inside Petgraph functions since they require NodeIndex as inputs and not u32.
The code following is what I have so far and the problem arises in the function find_node_index_with_name where the types seem to change even though I pass a vector of NodeIndex as input so when I iterate over it, I should also get NodeIndex back.
use petgraph::adj::NodeIndex;
use petgraph::stable_graph::StableGraph;
use petgraph::dot::Dot;
#[derive(Clone,Debug,Default)]
struct ControlBloc
{
name:String,
value:u32,
}
fn create_bloc(name:String,value:u32) -> ControlBloc
{
ControlBloc
{
name,
value,
}
}
fn find_node_index_with_name(gr:StableGraph<ControlBloc,u32> , nodes:Vec<NodeIndex> , name_search:String) -> Option<NodeIndex>
{
for i in 0..nodes.len()
{
if gr.node_weight(nodes[i]).unwrap().name == name_search
{
return nodes[i];
}
}
return None;
}
fn main() {
let mut graph = StableGraph::<ControlBloc,u32>::new();
let m = create_bloc(String::from("Main"),10);
let b1 = create_bloc(String::from("sub1"),20);
let b2 = create_bloc(String::from("sub2"),30);
let main = graph.add_node(m);
let sub1 = graph.add_node(b1);
let sub2 = graph.add_node(b2);
let all_nodes = vec![main,sub1,sub2];
println!("{:?}",find_node_index_with_name(graph, all_nodes, String::from("Main")));
}
I am a bit stumped as to why the types change.
Thank you for any inputs!
graph.add_node() returns a petgraph::graph::NodeIndex.
But you used petgraph::adj::NodeIndex which appears to be a different type (don't ask me why), thus the type mismatch.
I took the liberty to change a bit your code in order to use references where you used owned values.
use petgraph::graph::NodeIndex; // graph not adj
use petgraph::stable_graph::StableGraph;
#[derive(Clone, Debug, Default)]
struct ControlBloc {
name: String,
value: u32,
}
fn create_bloc(
name: String,
value: u32,
) -> ControlBloc {
ControlBloc { name, value }
}
fn find_node_index_with_name(
gr: &StableGraph<ControlBloc, u32>,
nodes: &[NodeIndex],
name_search: &str,
) -> Option<NodeIndex> {
nodes
.iter()
.map(|n| *n)
.find(|n| gr.node_weight(*n).unwrap().name == name_search)
/*
for i in 0..nodes.len() {
if gr.node_weight(nodes[i]).unwrap().name == name_search {
return Some(nodes[i]);
}
}
None
*/
}
fn main() {
let mut graph = StableGraph::<ControlBloc, u32>::new();
let m = create_bloc(String::from("Main"), 10);
let b1 = create_bloc(String::from("sub1"), 20);
let b2 = create_bloc(String::from("sub2"), 30);
let main = graph.add_node(m);
let sub1 = graph.add_node(b1);
let sub2 = graph.add_node(b2);
let all_nodes = vec![main, sub1, sub2];
for n in ["Main", "sub1", "sub2"] {
println!("{:?}", find_node_index_with_name(&graph, &all_nodes, n));
}
}
/*
Some(NodeIndex(0))
Some(NodeIndex(1))
Some(NodeIndex(2))
*/

Recursive closure inside a function [duplicate]

This is a very simple example, but how would I do something similar to:
let fact = |x: u32| {
match x {
0 => 1,
_ => x * fact(x - 1),
}
};
I know that this specific example can be easily done with iteration, but I'm wondering if it's possible to make a recursive function in Rust for more complicated things (such as traversing trees) or if I'm required to use my own stack instead.
There are a few ways to do this.
You can put closures into a struct and pass this struct to the closure. You can even define structs inline in a function:
fn main() {
struct Fact<'s> { f: &'s dyn Fn(&Fact, u32) -> u32 }
let fact = Fact {
f: &|fact, x| if x == 0 {1} else {x * (fact.f)(fact, x - 1)}
};
println!("{}", (fact.f)(&fact, 5));
}
This gets around the problem of having an infinite type (a function that takes itself as an argument) and the problem that fact isn't yet defined inside the closure itself when one writes let fact = |x| {...} and so one can't refer to it there.
Another option is to just write a recursive function as a fn item, which can also be defined inline in a function:
fn main() {
fn fact(x: u32) -> u32 { if x == 0 {1} else {x * fact(x - 1)} }
println!("{}", fact(5));
}
This works fine if you don't need to capture anything from the environment.
One more option is to use the fn item solution but explicitly pass the args/environment you want.
fn main() {
struct FactEnv { base_case: u32 }
fn fact(env: &FactEnv, x: u32) -> u32 {
if x == 0 {env.base_case} else {x * fact(env, x - 1)}
}
let env = FactEnv { base_case: 1 };
println!("{}", fact(&env, 5));
}
All of these work with Rust 1.17 and have probably worked since version 0.6. The fn's defined inside fns are no different to those defined at the top level, except they are only accessible within the fn they are defined inside.
As of Rust 1.62 (July 2022), there's still no direct way to recurse in a closure. As the other answers have pointed out, you need at least a bit of indirection, like passing the closure to itself as an argument, or moving it into a cell after creating it. These things can work, but in my opinion they're kind of gross, and they're definitely hard for Rust beginners to follow. If you want to use recursion but you have to have a closure, for example because you need something that implements FnOnce() to use with thread::spawn, then I think the cleanest approach is to use a regular fn function for the recursive part and to wrap it in a non-recursive closure that captures the environment. Here's an example:
let x = 5;
let fact = || {
fn helper(arg: u64) -> u64 {
match arg {
0 => 1,
_ => arg * helper(arg - 1),
}
}
helper(x)
};
assert_eq!(120, fact());
Here's a really ugly and verbose solution I came up with:
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
fn main() {
let weak_holder: Rc<RefCell<Weak<dyn Fn(u32) -> u32>>> =
Rc::new(RefCell::new(Weak::<fn(u32) -> u32>::new()));
let weak_holder2 = weak_holder.clone();
let fact: Rc<dyn Fn(u32) -> u32> = Rc::new(move |x| {
let fact = weak_holder2.borrow().upgrade().unwrap();
if x == 0 {
1
} else {
x * fact(x - 1)
}
});
weak_holder.replace(Rc::downgrade(&fact));
println!("{}", fact(5)); // prints "120"
println!("{}", fact(6)); // prints "720"
}
The advantages of this are that you call the function with the expected signature (no extra arguments needed), it's a closure that can capture variables (by move), it doesn't require defining any new structs, and the closure can be returned from the function or otherwise stored in a place that outlives the scope where it was created (as an Rc<Fn...>) and it still works.
Closure is just a struct with additional contexts. Therefore, you can do this to achieve recursion (suppose you want to do factorial with recursive mutable sum):
#[derive(Default)]
struct Fact {
ans: i32,
}
impl Fact {
fn call(&mut self, n: i32) -> i32 {
if n == 0 {
self.ans = 1;
return 1;
}
self.call(n - 1);
self.ans *= n;
self.ans
}
}
To use this struct, just:
let mut fact = Fact::default();
let ans = fact.call(5);

Different types of string.chars(), for .next() and .peek()

I'm trying to use string.chars().peekable() and the problem I have is that I have different types from .next() and .peek(). One is Option<char>, second is Option<&char>, and I have trouble to compare them.
My code is (s is String):
let mut left_iter = s.chars().peekable();
let mut right_iter = s.chars().rev().peekable();
loop {
let left = left_iter.next();
let right = right_iter.next();
let left_next = left_iter.peek();
let left_right = right_iter.peek();
if left == right || left == right_next {
...
}
The error I get is obvious:
expected &char, found char
But I can't find a way to have both next() and peek() having the same type without re/deconstructing Option.
Is there a clean way to have both return values having the same type?
You have two options derefenccing (&T -> T) one or referencing (T -> &T) the other:
Dereferencing
Since they are wrapped in Option, you could zip them and operate over with map, pattern match or dereference the referenced one, otherwise return false.:
fn main() {
let left = Some('c');
let right = Some(&'c');
println!("{}", right.zip(left).map(|(&r, l)| r == l).unwrap_or(false));
}
Playground
Or since char is Copy, you could use Option::copied:
fn main() {
let left = Some('c');
let right = Some(&'c');
println!("{}", left == right.copied());
}
Referencing
Also, and maybe simpler, you could use as_ref to get an Option<&T> from an Option<T>:
fn main() {
let left = Some('c');
let right = Some(&'c');
println!("{}", left.as_ref() == right);
}
Playground

Unwrap a BTreeSet in rust

In rust, the following function is legal:
fn unwrap<T>(s:Option<T>) -> T {
s.unwrap()
}
It takes ownership of s, panics if it is a None, and returns ownership of the contents of s (which is legal since an Option owns its contents).
I was trying to write a similar function with signature
fn unwrap_set<T>(s: BTreeSet<T>) -> T {
...
}
The idea is that it panics unless s has size 1, in which case it returns the single element. It seems like this should be possible for the same reason unwrap is possible, however none of the methods on BTreeSet had the right signature (they would need to have return type T). The closest was take, and I tried to do
let mut s2 = s;
let v: &T = s2.iter().next().unwrap();
s2.take(v).unwrap()
but this failed.
Is writing a function like unwrap_set possible?
The easiest way to do this would be to use BTreeSet<T>'s implementation of IntoIterator, which would allow you to easily pull owned values out of the set one at a time:
fn unwrap_set<T>(s: BTreeSet<T>) -> T {
let mut it = s.into_iter();
if let Some(first) = it.next() {
if let None = it.next() {
return first;
}
}
panic!("set must have a single value");
}
If you wanted to indirectly rely on IntoIterator you could also use a normal loop, but I don't think it's as readable that way so I probably wouldn't do this:
fn unwrap_set<T>(s: BTreeSet<T>) -> T {
let mut result = None;
for item in s {
// If there is a second value, bail out
if let Some(_) = result {
result = None;
break;
}
result = Some(item);
}
return result.expect("set must have a single value");
}

Possible to combine assignment and comparison in an expression?

In C, it's common to assign and compare in a single expression:
n = n_init;
do {
func(n);
} while ((n = n.next) != n_init);
As I understand it this can be expressed in Rust as:
n = n_init;
loop {
func(n);
n = n.next;
if n == n_init {
break;
}
}
Which works the same as the C version (assuming the body of the loop doesn't use continue).
Is there a more terse way to express this in Rust, or is the example above ideal?
For the purposes of this question, assume ownership or satisfying the borrow checker isn't an issue. It's up to developer to satisfy these requirements.
For example, as an integer:
n = n_init;
loop {
func(&vec[n]);
n = vec[n].next;
if n == n_init {
break;
}
}
This may seem obvious that the Rust example is idiomatic Rust - however I'm looking to move quite a lot of this style of loop to Rust, I'm interested to know if there is some better/different way to express it.
The idiomatic way to represent iteration in Rust is to use an Iterator. Thus you would implement an iterator that does the n = n.next and then use a for loop to iterate over the iterator.
struct MyIter<'a> {
pos: &'a MyData,
start: &'a MyData,
}
impl<'a> Iterator for MyIter<'a> {
type Item = &'a MyData;
fn next(&mut self) -> Option<&'a MyData> {
if self.pos as *const _ == self.start as *const _ {
None
} else {
let pos = self.pos;
self.pos = self.pos.next;
Some(pos)
}
}
}
it is left as an exercise to the reader to adapt this iterator to be able to start from the first element instead of starting from the second.
Rust supports pattern matching in if and while:
instead of having a boolean condition, the test is considered successful if the pattern matches
as part of pattern matching, you bind the values matched to names
Thus, if instead of having a boolean condition you were building an Option...
fn check(next: *mut Node, init: *mut Node) -> Option<*mut Node>;
let mut n = n_init;
loop {
func(n);
if let Some(x) = check(n.next, n_init) {
n = x;
} else {
break;
}
}
However, if you can use an Iterator instead you'll be much more idiomatic.
An assignment in Rust returns the empty tuple. If you are fine with non-idiomatic code you can compare the assignment-result with such an empty tuple and use a logical conjunction to chain your actual loop condition.
let mut current = 3;
let mut parent;
while (parent = get_parent(current)) == () && parent != current {
println!("currently {}, parent is {}", current, parent);
current = parent;
}
// example function
fn get_parent(x: usize) -> usize {
if x > 0 { x - 1 } else { x }
}
// currently 3, parent is 2
// currently 2, parent is 1
// currently 1, parent is 0
This has the disadvantage that entering the loop needs to run logic (which you can avoid with C's do {..} while(); style loops).
You can use this approach inside a do-while macro, but readability isn't that great and at that point a refactoring might be preferable. In any case, this is how it could look:
do_it!({
println!("{}", n);
} while (n = n + 1) == () && n < 4);
This is the code for the macro:
macro_rules! do_it {
($b: block while $e:expr) => {
loop {
$b
if !($e) { break };
}
}
}

Resources