How can I port this C++ code to Rust:
auto sgnR = (R >= 0.) ? 1. : -1.;
I have seen some examples with the match keyword, but I don't understand how it works.
Rust does not have the ternary operator because it's not needed. Everything evaluates to some value, and if / else statements are no exception:
let r = 42.42;
let sgn_r = if r >= 0. { 1. } else { -1. };
You'll note that I've also changed your variable names to be idiomatic Rust. Identifiers use snake_case.
Do not be confused by the ? operator that Rust does have. This is called the "try operator" and is used to propagate errors.
Specifically for this code, it's likely you should use f64::signum:
let r = 42.42_f64;
let sgn_r = r.signum();
You can use bool::then or in this case, the non-lazy bool::then_some to accomplish the same thing:
let sgn_r = (r >= 0).then_some(1).unwrap_or(-1);
An if/else statement is probably better for readability, but this may be nicer in certain cases.
I like to implement a similar construct using a trait:
pub trait IfElse {
fn ifelse<T>(&self, iftrue: T, iffalse: T) -> T;
}
impl IfElse for bool {
fn ifelse<T>(&self, iftrue: T, iffalse: T) -> T {
if *self { iftrue }
else { iffalse }
}
}
Then it can be used like this:
let sng_r = (r >= 0).ifelse(1, -1);
Related
I was doing an exercise on exercism with Rust and came across a community solution where the implementation of the given user confused me.
pub struct Position(pub i16, pub i16);
impl Position {
pub fn manhattan(&self) -> i16 {
let Position(x, y) = self;
x.abs() + y.abs()
}
}
What I do not understand is:
let Position(x, y) = self;
x.abs() + y.abs()
As I understand it, I am initializing a struct of Position, but how am I initializing it without setting it equal to a variable? Further more, how am I then able to suddenly have access to the arguments?
What you see here is called destructuring, and is actually creating variables x and y from self.
In this case, if you were to take this line of code:
let Position(x, y) = self;
What this is actually saying is equilalent to this:
let x = &self.0;
let y = &self.1;
You can think of the Position(x, y) part of the assignment as a pattern. You will see pattern matching in many places in Rust, most commonly in match statements. For example, unwrapping a variable of type Option<String> might look like:
match some_optional_string {
Some(value) => println!("Got value: {value}"),
None => println!("Got no value")
};
Pattern matching also appears in conditions as well.
if let Some(value) = some_optional_string {
println!("Got value: {value}");
}
Another way to think of the particular example that you are referring to, is to replace self with its actual value. Say for example self was initialized with the values 3 and 4, this might look like so:
let some_position = Position(3, 4);
Now if you were to call some_position.manhatten(), self is equivalent to a &Position(3, 4)
If you replace all uses of self in the function with the value:
let Position(x, y) = &Position(3, 4);
x.abs() + y.abs()
(This won't actually compile because of lifetimes, but this is beside the point)
You can see more clearly now that Position(x, y) matches &Position(3, 4) but assigning x and y to &3 and &4
I saw you were also learning Haskell, which has a very similar concept. In haskell you could have a function that took in a Maybe value, and have different definitions based on which it matched.
someFunc :: Maybe String -> String
someFunc (Just value) = value
someFunc Nothing = "I'm a different string"
Which has the same concept of destructuring or matching.
Hopefully this rambling makes sense!
I'm working on a rust project written a couple of years ago, and have come across this piece of code, which is literally:
let mut values = vec![];
for x in maybe_values {
if let Some(x) = x {
values.push(Arc::new(x));
}
}
I understand that "if let" introduces a pattern-matching if (Which seems to be a poor re-use of the keyword "let", but I will get over that - If anyone can help me with a mental mnemonic to make sense of "let" here, please do!).
But what is the test Some(x) = x doing?
From my testing, it seems to be a trick/idiom to both a) test that the loop variant 'x' is Some(), and also b) end up with the unwrap()ped value in x.
But I can't fully explain it to myself, and can't find reference to this being an idiom anywhere.
Hope you can help my Rust education path. Thanks.
This is a shorthand for using a full match statement when you only care about matching a single use case.
So this block of code:
if let x = y {
foo();
} else {
bar();
}
Is equivalent to using a full match:
match y {
x => {
foo();
}
_ => {
bar();
}
}
For your specific case, it is equivalent to this. The inner x uses the same name as the outer variable which can be confusing, but they are two separate values.
let mut values = vec![];
for x in maybe_values {
match x {
Some(y) => values.push(Arc::new(y)),
_ => {},
}
}
There are two completely different variables in play here. It's equivalent to.
let mut values = vec![];
for x_1 in maybe_values {
if let Some(x_2) = x_1 {
values.push(Arc::new(x_2));
}
}
In Rust, the right-hand side of a let is evaluated with the left-hand variable not in scope, so when the if let is evaluated, the outer x is still in-scope. Then, if it's a Some value, we make a new variable x which contains the inside of the Option. This variable shadows the previous x, making it inaccessible inside the if statement (in the same way that a function argument called x would render a global variable named x inaccessible by shadowing).
Basically, I want to implement custom operator in Rust.
One is pipeline-operator that is on T.
operator overloading only works for local structures so not usable for type T.
On the other hand, apply::Apply does work on T
/// Represents a type which can have functions applied to it (implemented
/// by default for all types).
pub trait Apply<Res> {
/// Apply a function which takes the parameter by value.
fn apply<F: FnOnce(Self) -> Res>(self, f: F) -> Res
where Self: Sized {
f(self)
}
}
impl<T: ?Sized, Res> Apply<Res> for T {
// use default definitions...
}
let string = 1.apply(|x| x * 2).apply(|x: i32| x.to_string());
However, I don't like this .apply syntax. It's the same as Prototype Pollution in JavaScript and can collide with some-structure.apply
In any case, I prefer binary operator like
let string = 1 |> (|x| x * 2) |> (|x: i32| x.to_string());
So my question is:
Writing the code above with a binary operator such as |>, is it possible to transpile the code (Macro input) to something (Macro output) like
let string = 1.myownapply(|x| x * 2).myownapply(|x: i32| x.to_string());
myownapply can be a much longer strings to avoid the collision.
I've read Procedural Macros in Rust can do anything, so is this possible?
If this is not so hard, I appreciate if you provide a sample code.
This should be possible with macro_rules!, see https://doc.rust-lang.org/rust-by-example/macros.html and https://doc.rust-lang.org/reference/macros-by-example.html. Try something like this:
macro_rules! pipeline {
($expr:expr $(=> $func:expr)+) => {
$expr $(.apply($func))+
}
}
I ran into a Rustlings exercise that keeps bugging me:
pub fn factorial(num: u64) -> u64 {
// Complete this function to return factorial of num
// Do not use:
// - return
// For extra fun don't use:
// - imperative style loops (for, while)
// - additional variables
// For the most fun don't use:
// - recursion
// Execute `rustlings hint iterators4` for hints.
}
A hint to solution tells me...
In an imperative language you might write a for loop to iterate
through multiply the values into a mutable variable. Or you might
write code more functionally with recursion and a match clause. But
you can also use ranges and iterators to solve this in rust.
I tried this approach, but I am missing something:
if num > 1 {
(2..=num).map(|n| n * ( n - 1 ) ??? ).???
} else {
1
}
Do I have to use something like .take_while instead of if?
The factorial is defined as the product of all the numbers from a starting number down to 1. We use that definition and Iterator::product:
fn factorial(num: u64) -> u64 {
(1..=num).product()
}
If you look at the implementation of Product for the integers, you'll see that it uses Iterator::fold under the hood:
impl Product for $a {
fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
iter.fold($one, Mul::mul)
}
}
You could hard-code this yourself:
fn factorial(num: u64) -> u64 {
(1..=num).fold(1, |acc, v| acc * v)
}
See also:
How to sum the values in an array, slice, or Vec in Rust?
How do I sum a vector using fold?
Although using .product() or .fold() is probably the best answer, you can also use .for_each().
fn factorial(num: u64) -> u64 {
let mut x = 1;
(1..=num).for_each(|i| x *= i);
x
}
When using below function:
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i: BigInt = ToBigInt::to_bigint(&2).unwrap();
let mut factors = Vec::<BigInt>::new();
while i * i <= n {
if (n % i) == ToBigInt::to_bigint(&1).unwrap() {
i = i + ToBigInt::to_bigint(&1).unwrap();
}
else {
n = n/i as BigInt;
factors.push(i);
}
i = i + ToBigInt::to_bigint(&1).unwrap();
}
if n > i {
factors.push(n);
}
factors
}
I get moved value errors for literally every time i or n is used, starting from the line with while, also in the if. I have read about borrowing, which I understand decently, but this thing I don't understand.
I am not "copying" the value at all, so I don't see anywhere were I could lose ownership of the variables.
Mul (and the other arithmetic operators) take the parameters by value, so i * i move the value i (this is not a problem for primitive numbers because they implement Copy - BigInt does not).
As Mul is implemented for (two) &BigInt, you can do the multiplication (and the other arithmetic operations) with &:
use num::*;
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i = BigInt::from(2);
let mut factors = Vec::new();
while &i * &i <= n {
if (&n % &i) == BigInt::one() {
i = i + BigInt::one();
} else {
n = n / &i;
factors.push(i.clone());
}
i = i + BigInt::one();
}
if n > i {
factors.push(n);
}
factors
}
Note that I also made some simplifications, like omitting the type on Vec::new and using BigInt::from (cannot fail).
Remember that operators in Rust are just syntactic sugar for function calls.
a + b translates to a.add(b).
Primitive types such as i32 implement the trait Copy. Thus, they can be copied into such an add function and do not need to be moved.
I assume the BigInt type you are working with does not implement this trait.
Therefore, in every binary operation you are moving the values.