Generics<T> that accept String, &str and primitive value - rust

I apologize in advance as this may somewhat dumb question.
I was trying to create the function that simply return the bool result of
whether the given value is prime number or not.
I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
pub fn prime<T>(val: T) -> bool
where T: ToPrimitive {
let val = val.to_i64().unwrap();
for i in 2..=val {
if val % i == 0 {
return false;
}
if i*i >= val {
break;
}
}
true
}

If you are concerned with performance, leave it as is. You are already accepting all integer types. Conversion from strings should happen elsewhere. (as already mentioned by the other answers)
That said, to actually fulfill your request, here is a horribly inefficient but simple solution to your problem :)
pub fn prime<T>(val: T) -> bool
where
T: ToString,
{
let val: u64 = val.to_string().parse().unwrap();
for i in 2..val {
if val % i == 0 {
return false;
}
if i * i >= val {
break;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
println!("{:?}", prime("17"));
println!("{:?}", prime(String::from("17")));
}
true
true
true
On a more serious note ... your own solution and all of the answers convert the input into another type.
If you skip that and instead use the given type directly, you could potentially get a speed boost.
For that to work, though, I had to switch from i * i >= val to ..=val.sqrt().
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
for i in num::range_inclusive(two, val.sqrt()) {
if val % i == T::zero() {
return false;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
}
true
As a further note, you could rewrite the entire for loop with the all iterator method:
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
num::range_inclusive(two, val.sqrt()).all(|i| val % i != T::zero())
}
fn main() {
println!("{:?}", prime(17));
}
true

I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
You'd have to create your own trait to unify the feature: while Rust has grown the TryFrom trait, in the stdlib currently it's only used for faillible integer -> integer conversions (e.g. i64 to u8). String -> integer conversions remain on the older FromStr trait, and it's unclear that there's any plan to migrate.
I would agree with #cameron1024 though, doing this conversion in the callee increases the complexity without making much sense, if the callee takes a string I would expect it to handle and report validation / conversion errors to the source of the values. The prime of a string doesn't really make sense.

Firstly, do you really want to be able to check if strings are prime? You probably don't want someone to be able to write prime("hello").
Assuming you're fine with numbers, I'd just use Into<u128> as the trait bound:
fn prime<T: Into<u128>>(t: T) -> bool {
let val = t.into();
// rest of the logic
}
So what about strings and signed integers?
IMO, you should convert these at the call-site, which allows for better error handling, rather than just unwrap():
/// strings
prime("123".parse()?);
prime(String::from("123").parse()?);
/// signed ints
prime(u128::try_from(123i8)?);
This way, you can use ? to correctly handle errors, and make prime panic-free.
If you really want to not have to convert at the callsite, you could use a custom trait:
trait TryIntoU128 {
type Error;
fn try_into_u128(self) -> Result<u128, Self::Error>;
}
Then you could implement this on various types:
impl TryIntoU128 for String {
type Error = ParseIntError;
fn try_into_u128(self) -> Result<u128, Self::Error> {
self.parse()
}
}
// etc
Then you can use this trait bound for your prime function instead

Related

binary assignment operation `+=` cannot be applied to type `&str`

pub fn is_palindrome(x: i32) -> bool {
let mut rev = "";
for n in x.to_string().chars().rev() {
rev += n
}
return false
}
I'm used to writing this syntax in languages like kotlin, but how should I do this in rust?
"" is an empty string-slice, i.e. a reference to the storage where a sequence of utf-8 characters is placed (actually, it's a sequence of bytes conforming to utf-8 encoding, but that is not exactly the main concern in this question).
In general, with a string-slice, nothing says how those characters were stored, thus we cannot change anything to this storage (extend/remove) and moreover a string-slice (&str) is a shared (immutable) reference to this storage preventing from any change.
In this peculiar case (a literal as " ... ") the characters are stored in constant memory (consistent with a shared reference) at the process startup.
To extend such a sequence, you need to control how it is stored.
In this case, we don't use a string-slice but a String which allocates on the heap the storage for the sequence according to the needs.
And, of course, since a String owns its content, it can mutate it (if the String itself is considered mutable).
Appending a char to a String is done with the .push() function.
pub fn is_palindrome(x: i32) -> bool {
let mut rev = String::new();
for n in x.to_string().chars().rev() {
rev.push(n);
}
return false;
}
The other answers are of course correct and one of them should be the accepted answer.
I'd just like to point out that the construct for n in iter { y.append(n) } is used so many times that it got implemented in a method of Iterator: collect().
pub fn is_palindrome(x: i32) -> bool {
let rev = x.to_string().chars().rev().collect::<String>();
return false;
}
Another remark: to compute whether the forward and reverse of a string are identical, you don't actually need to create the reversed string. You can directly compare its iterators:
pub fn is_palindrome(x: i32) -> bool {
let x_str = x.to_string();
x_str.chars().eq(x_str.chars().rev())
}
AddAssign<&str> is implemented for String. Thus you can use += on String.
A simple example:
pub fn is_palindrome(x: i32) -> bool {
let mut rev = String::new();
for n in x.to_string().chars().rev() {
rev += &n.to_string();
}
return false
}

Is there a Rust equivalent to C++'s operator bool() to convert a struct into a boolean?

In C++, we can overload operator bool() to convert a struct to bool:
struct Example {
explicit operator bool() const {
return false;
}
};
int main() {
Example a;
if (a) { /* some work */ }
}
Can we do something simple (and elegant) in Rust so to:
pub struct Example {}
fn main() {
let k = Example {};
if k {
// some work
}
}
There's no direct equivalent of operator bool(). A close alternative would be to implement From (which will also implement Into) and call the conversion explicitly:
pub struct Example;
impl From<Example> for bool {
fn from(_other: Example) -> bool {
false
}
}
fn main() {
let k = Example;
if k.into() {
// some work
}
}
This will take ownership of Example, meaning you can't use k after it's been converted. You could implement it for a reference (impl From<&Example> for bool) but then the call site becomes uglier ((&k).into()).
I'd probably avoid using From / Into for this case. Instead, I'd create a predicate method on the type. This will be more readable and can take &self, allowing you to continue using the value.
See also:
When should I implement std::convert::From vs std::convert::Into?
Rust does not have C++'s implicit type conversion via operator overloading. The closest means of implicit conversion is through a Deref impl, which provides a reference of a different type.
What is possible, albeit not necessarily idiomatic, is to implement the not operator ! so that it returns a boolean value, and perform the not operation twice when needed.
use std::ops::Not;
pub struct Example;
impl Not for Example {
type Output = bool;
fn not(self) -> bool { false }
}
fn main() {
let k = Example;
if !!k {
println!("OK!");
} else {
println!("WAT");
}
}
Playground
You have a few options, but I'd go for one of these:
Into<bool> (From<Example>)
If your trait conceptually represents a bool, but maybe with some extra metadata, you can implement From<Example> for bool:
impl From<Example> for bool {
fn from(e: Example) {
// perform the conversion
}
}
Then you can:
fn main() {
let x = Example { /* ... */ };
if x.into() {
// ...
}
}
Custom method
If your type doesn't really represent a boolean value, I'd usually go for an explicit method:
impl Example {
fn has_property() -> bool { /* ... */ }
}
This makes it more obvious what the intent is, for example, if you implemented From<User> for bool:
fn main() {
let user = User { /* ... */ };
if user.into() {
// when does this code get run??
}
// compared to
if user.logged_in() {
// much clearer
}
}
You can implement std::ops::Deref with the bool type. If you do that, you have to call *k to get the boolean.
This is not recommended though, according to the Rust documentation:
On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.
struct Example {}
impl std::ops::Deref for Example {
type Target = bool;
fn deref(&self) -> &Self::Target {
&true
}
}
fn main() {
let k = Example {};
if *k {
// some work
}
}
Playground

How to I make a variable available to a function without passing it or using a global, or should I take a different approach? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm writing a function to fix the float precision problem in rust (among other languages). I need to choose to .floor() or .ceil() within the function based on the passed parameter. Whats the best way to approach this problem. If something other than a function serves the propose better, by all means! Thank you for your help!
fn main() {
to_round(7.987, "floor");
}
fn to_round(n: f64, floor_or_ceil: &str) -> f64 {
fn test(diff_n: f64) -> f64 {
if floor_or_ceil == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
}
test(n)
}
If you replace your inner fn function with a closure, then the code you have will compile. Closures can refer to variables from the enclosing scope, whereas fns cannot.
fn main() {
to_round(7.987, "floor");
}
fn to_round(n: f64, floor_or_ceil: &str) -> f64 {
let test = |diff_n: f64| -> f64 {
if floor_or_ceil == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
};
test(n)
}
However, closures do come with some caveats; in particular, they can't be generic functions, and can't be used where function pointers can be (unless they don't mention ("close over") any variables from the enclosing scope and are merely using closure syntax instead of fn syntax).
The most general-purpose clean solution to this class of problem is to explicitly pass the needed parameters, but you can minimize the clutter of it by such means as using a struct (especially if there is more than one value needed) and making the functions methods of that struct:
fn main() {
let c = MathContext { rounding_mode: "floor" };
c.to_round(7.987);
}
struct MathContext {
rounding_mode: &'static str, // Side note: this should really be an enum, not a string
// And you can add more fields here for any other parameters needed.
}
impl MathContext {
fn to_round(&self, n: f64) -> f64 {
self.test(n)
}
fn test(&self, diff_n: f64) -> f64 {
if self.rounding_mode == "floor" {
diff_n.floor()
} else {
diff_n.ceil()
}
}
}
Whether exactly this set of methods fits depends on what you're actually doing; if test is very specific to to_round then it doesn't make sense to pull it out this way. But it seems likely that this pattern might be useful elsewhere in your code, at least, if you're doing things like picking which way to round numbers.
First, you should eliminate the use of &strs as enums. Just declare an enum:
#[derive(Clone, Copy)]
enum Round {
Floor,
Ceil,
}
use ::Round::{Floor, Ceil};
fn round(n: f64, setting: Round) -> f64 {
match setting {
Floor => n.floor(),
Ceil => n.ceil(),
}
}
The second variant is using closures.
fn round_func(setting: Round) -> impl Fn(f64) -> f64 {
move |n| match setting {
Floor => n.floor(),
Ceil => n.ceil(),
}
}
This will take as input your setting and return a closure that will calculate either the floor or ceiling for you. EG you could do something like
let closure = round_func(setting);
println!("{}", closure(5.5));
println!("{}", closure(5.5));
This will take as input the configuration and return a closure that serves as a function.
In this particular case, we can actually do even better by directly returning a function pointer. The code looks like this:
fn round_func_pointer(setting: Round) -> fn(f64) -> f64 {
match setting {
Floor => f64::floor,
Ceil => f64::ceil,
}
}
The code could also be written
fn round_func_pointer(setting: Round) -> fn(f64) -> f64 {
match setting {
Floor => |n| n.floor(),
Ceil => |n| n.ceil(),
}
}
This works because the "closure" |n| n.floor() actually doesn't capture anything at all (no move keyword necessary), and therefore is compiled to a function pointer.
Class variable w/ precision and rounding mode
Rust doesn't have syntax for declaring a field in a struct as static like C++, Java, and other languages. However, it is still possible to declare a static variable that for all intents and purposes is a "class variable".
In the implementation below, the scope of the static variable CONFIG is restricted to the file it's declared in; so, in that sense it isn't a "global" variable. The struct declared within the same file has exclusive access to it, and all instances of that struct access the same variable.
To ensure that the "class variable" doesn't get clobbered by simultaneous writes from separate threads, RwLock is used to synchronize it. This incurs a small cost in performance over implementations that don't synchronize access in single-threaded environments.
The lazy_static macro sets up the "class variable" to delay initialization until the variable is actually needed at runtime.
use std::sync::RwLock;
#[macro_use]
extern crate lazy_static;
lazy_static! {
// The tuple holds (rounding-mode, precision).
static ref CONFIG: RwLock<(RoundMode, u32)> = {
RwLock::new((RoundMode::Auto, 3))
};
}
#[derive(Clone, Copy)]
pub enum RoundMode { Ceil, Floor, Auto }
The struct implementation below provides a way for client code to set the rounding mode (Auto, Ceil, and Floor) and precision (number of decimal positions to round to) for all instances of HasValue.
pub struct HasValue { value: f64 }
impl HasValue {
pub fn new(value: f64) -> Self
{
HasValue { value }
}
pub fn config() -> (RoundMode, u32)
{
*CONFIG.read().unwrap()
}
pub fn set_config(mode: RoundMode, precision: u32)
{
*CONFIG.write().unwrap() = (mode, precision);
}
pub fn round(&self) -> f64
{
use RoundMode::*;
let (mode, prec) = HasValue::config();
let base = 10_f64.powf(prec as f64);
match mode {
Auto => (self.value * base).round() / base,
Ceil => (self.value * base).ceil() / base,
Floor => (self.value * base).floor() / base,
}
}
}
Creating, configuring, printing...
fn main()
{
let v = HasValue::new(7.98555);
let r = v.round();
println!("r={:?}", r);
HasValue::set_config(RoundMode::Floor, 4);
let r = v.round();
println!("r={:?}", r);
}

Using convert::Into with enum to unwrap and convert value

I'm starting to get comfortable with Rust, but there are still some things that are really tripping me up with lifetimes. In this particular case, what I want to do is have an enum which may have different types wrapped as a generic parameter class to create strongly typed query parameters in a URL, though the specific use case is irrelevant, and return a conversion of that wrapped value into an &str. Here's an example of what I want to do:
enum Param<'a> {
MyBool(bool),
MyLong(i64),
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, &'a str) {
match self {
Param::MyBool(b) => ("my_bool", &b.to_string()), // clearly wrong
Param::MyLong(i) => ("my_long", &i.to_string()), // clearly wrong
Param::Value(s) => ("my_str", s),
}
}
}
What I ended up doing is this to deal with the obvious lifetime issue (and yes, it's obvious to me why the lifetime isn't long enough for the into() function):
enum Param<'a> {
MyBool(&'a str), // no more static typing :(
MyLong(&'a str), // no more static typing :(
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, &'a str) {
match self {
Param::MyBool(b) => ("my_bool", b),
Param::MyLong(i) => ("my_long", i),
Param::Value(s) => ("my_str", s),
}
}
}
This seems like an ugly workaround in a case where what I really want to do is guarantee the static typing of certain params, b/c now it's the constructor of the enum that's responsible for the proper type conversion. Curious if there is a way to do this... and yes, at some point I need &str as that is a parameter elsewhere, specifically:
let body = url::form_urlencoded::serialize(
vec![Param::MyBool(&true.to_string()).
into()].
into_iter());
I went through a whole bunch of things like trying to return String instead of &str from into(), but that only caused conversion issues down the line with a map() of String -> &str. Having the tuple correct from the start is the easiest thing, rather than fighting the compiler at every turn after that.
-- update--
Ok, so I went back to a (String,String) tuple in the into() function for the enum. It turns out that there is an "owned" version of the url::form_urlencoded::serialize() function which this is compatible with.
pub fn serialize_owned(pairs: &[(String, String)]) -> String
But, now I'm also trying to use the same pattern for the query string in the hyper::URL, specifically:
fn set_query_from_pairs<'a, I>(&mut self, pairs: I)
where I: Iterator<Item=(&'a str, &'a str)>
and then I try to use map() on the iterator that I have from the (String,String) tuple:
params: Iterator<Item=(String, String)>
url.set_query_from_pairs(params.map(|x: (String, String)| ->
(&str, &str) { let (ref k, ref v) = x; (k, v) } ));
But this gets error: x.0 does not live long enough. Ref seems correct in this case, right? If I don't use ref, then it's k/v that don't live long enough. Is there something 'simple' that I'm missing in this?
It is not really clear why you can't do this:
enum Param<'a> {
MyBool(bool),
MyLong(i64),
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, String) {
match self {
Param::MyBool(b) => ("my_bool", b.to_string()),
Param::MyLong(i) => ("my_long", i.to_string()),
Param::MyStr(s) => ("my_str", s.into()),
}
}
}
(into() for &str -> String conversion is slightly more efficient than to_string())
You can always get a &str from String, e.g. with deref coercion or explicit slicing.

How to achieve equivalent of take_while on a slice?

Rust slices do not currently support some iterator methods, i.e. take_while. What is the best way to implement take_while for slices?
const STRHELLO:&'static[u8] = b"HHHello";
fn main() {
let subslice:&[u8] = STRHELLO.iter().take_while(|c|(**c=='H' as u8)).collect();
println!("Expecting: {}, Got {}",STRHELLO.slice_to(3),subslice);
assert!(subslice==STRHELLO.slice_to(3));
}
results in the error:
<anon>:6:74: 6:83 error: the trait `core::iter::FromIterator<&u8>` is not implemented for the type `&[u8]`
This code in the playpen:
http://is.gd/1xkcUa
First of all, the issue you have is that collect is about creating a new collection, while a slice is about referencing a contiguous range of items in an existing array (be it dynamically allocated or not).
I am afraid that due to the nature of traits, the fact that the original container (STRHELLO) was a contiguous range has been lost, and cannot be reconstructed after the fact. I am also afraid that any use of "generic" iterators simply cannot lead to the desired output; the type system would have to somehow carry the fact that:
the original container was a contiguous range
the chain of operations performed so far conserve this property
This may be doable or not, but I do not see it done now, and I am unsure in what way it could be elegantly implemented.
On the other hand, you can go about it in the do-it-yourself way:
fn take_while<'a>(initial: &'a [u8], predicate: |&u8| -> bool) -> &'a [u8] { // '
let mut i = 0u;
for c in initial.iter() {
if predicate(c) { i += 1; } else { break; }
}
initial.slice_to(i)
}
And then:
fn main() {
let subslice: &[u8] = take_while(STRHELLO, |c|(*c==b'H'));
println!("Expecting: {}, Got {}",STRHELLO.slice_to(3), subslice);
assert!(subslice == STRHELLO.slice_to(3));
}
Note: 'H' as u8 can be rewritten as b'H' as show here, which is symmetric with the strings.
It is possible via some heavy gymnastics to implement this functionality using the stock iterators:
use std::raw::Slice;
use std::mem::transmute;
/// Splice together to slices of the same type that are contiguous in memory.
/// Panics if the slices aren't contiguous with "a" coming first.
/// i.e. slice b must follow slice a immediately in memory.
fn splice<'a>(a:&'a[u8], b:&'a[u8]) -> &'a[u8] {
unsafe {
let aa:Slice<u8> = transmute(a);
let bb:Slice<u8> = transmute(b);
let pa = aa.data as *const u8;
let pb = bb.data as *const u8;
let off = aa.len as int; // Risks overflow into negative!!!
assert!(pa.offset(off) == pb, "Slices were not contiguous!");
let cc = Slice{data:aa.data,len:aa.len+bb.len};
transmute(cc)
}
}
/// Wrapper around splice that lets you use None as a base case for fold
/// Will panic if the slices cannot be spliced! See splice.
fn splice_for_fold<'a>(oa:Option<&'a[u8]>, b:&'a[u8]) -> Option<&'a[u8]> {
match oa {
Some(a) => Some(splice(a,b)),
None => Some(b),
}
}
/// Implementaton using pure iterators
fn take_while<'a>(initial: &'a [u8],
predicate: |&u8| -> bool) -> Option<&'a [u8]> {
initial
.chunks(1)
.take_while(|x|(predicate(&x[0])))
.fold(None, splice_for_fold)
}
usage:
const STRHELLO:&'static[u8] = b"HHHello";
let subslice: &[u8] = super::take_while(STRHELLO, |c|(*c==b'H')).unwrap();
println!("Expecting: {}, Got {}",STRHELLO.slice_to(3), subslice);
assert!(subslice == STRHELLO.slice_to(3));
Matthieu's implementation is way cleaner if you just need take_while. I am posting this anyway since it may be a path towards solving the more general problem of using iterator functions on slices cleanly.

Resources