So obviously I could do something like:
impl From<RangeInclusive<u32>> for Range<u32>{
fn from(r: RangeInclusive<u32>) -> Self {
(*r.start()..(r.end()+1))
}
}
However I was wondering if there was already a standard function for this?(I was unable to find anything in docs/ after a quick Google).
If not how would one go about implementing this for every num type, and would such an implementation be welcome to rust, or is there a reason why this is not already implemented?
Not every RangeInclusive can be converted to a Range, which is a major reason for RangeInclusive to exist. For instance, 0u32..=u32::MAX cannot be converted to Range<u32> because u32::MAX + 1 is out of range for u32.
It's conceivable that Range<u32> could implement TryFrom<RangeInclusive<u32>>, but such conversion should rarely be necessary. Instead of converting between different kinds of ranges, you should usually write generic APIs using RangeBounds.
Related
The trait documentation says
Display is similar to Debug, but Display is for user-facing output, and so cannot be derived.
But what does that mean? Should it write the full string-encoded value even if that results in a 500 character output? Should it make a nice and friendly representation suitable for display in a user interface even if that results in to_string() not actually returning the full value as a string?
Let me illustrate:
Say I have a type that represents important data in my application. This data has a canonical string-encoding with a very specific format.
pub struct BusinessObject {
pub name: String,
pub reference: u32,
}
First, I want to implement Display so I can use it for making easily readable log messages:
impl Display for BusinessObject {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Formats like `Shampoglak (7384)`
write!(f, "{} ({})", self.name, self.reference)
}
}
Now, let's implement a method that returns the canonical standard string format for BusinessObject instances. As the as_str() method name is idiomatically only used when returning a string slice and that is not possible in this case, one could think that the most straightforward approach would be to implement a method to_string() for this.
impl BusinessObject {
fn to_string(&self) -> String {
// Formats like `Shampoglak00007384`
format!("{}{:0>8}", self.name, self.reference)
}
}
But no! This method name is already implemented as part of the automatic ToString trait implementation that we have because we implemented Display.
What does an idiomatic implementation of Display write? A full representation of a value as a string or a friendly, human-readable representation of it? How should I structure my code and name my methods if I need to implement both of those? I am specifically looking for a solution that can be applied generically and not just in this specific situation. I don't want to have to look up what the behavior of to_string() for a given struct is before I use it.
I didn't find anything in the documentation of associated traits and various Rust books and resources I looked into.
What does an idiomatic implementation of Display write? A full representation of a value as a string or a friendly, human-readable representation of it?
The latter: Display should produce a friendly, human-readable representation.
How should I structure my code and name my methods if I need to implement both of those?
"Full representations" of values as strings would more correctly be known as a string serialisation of the value. A method fn into_serialised_string(self) -> String would be one approach, but perhaps you want to consider a serialisation library like serde that separates the process of serialising (and deserialising) from the serialised format?
What does an idiomatic implementation of Display write?
It writes the obvious string form of that data. What exactly that will be depends on the data, and it may not exist for some types.
Such a string representation is not necessarily “human friendly”. For example, the Display implementation of serde_json::Value (a type which represents arbitrary JSON data structures) produces the JSON text corresponding to the value, by default without any whitespace for readability — because that's the conventional string representation.
Display should be implemented for types where you can say there is “the string representation of the data” — where there is one obvious choice. In my opinion, it should not be implemented for types where there isn't one obvious choice — instead, the API should omit it, in order to guide users of the type to think about which representation they want, rather than giving them a potentially bad default.
A full representation of a value as a string or a friendly, human-readable representation of it?
In my opinion, a Display implementation which truncates the data is incorrect. Display is for the string form of the data, not a name or snippet of the data.
How should I structure my code and name my methods if I need to implement both of those?
For convenient use in format strings, you can write one or more methods which return wrapper types that implements Display (like Path::display() in std).
I wrote a program where I manipulated a lot of BigInt and BigUint values and perform some arithmetic operations.
I produced code where I frequently used BigInt::from(Xu8) because it is not possible to directly add numbers from different types (if I understand correctly).
I want to reduce the number of BigInt::from in my code. I thought about a function to "wrap" this, but I would need a function for each type I want to convert into BigInt/BigUint:
fn short_name(n: X) -> BigInt {
return BigInt::from(n)
}
Where X will be each type I want to convert.
I couldn't find any solution that is not in contradiction with the static typing philosophy of Rust.
I feel that I am missing something about traits, but I am not very comfortable with them, and I did not find a solution using them.
Am I trying to do something impossible in Rust? Am I missing an obvious solution?
To answer this part:
I produced code where I frequently used BigInt::from(Xu8) because it is not possible to directly add numbers from different types (if I understand correctly).
On the contrary, if you look at BigInt's documentation you'll see many impl Add:
impl<'a> Add<BigInt> for &'a u64
impl Add<u8> for BigInt
and so on. The first allows calling a_ref_to_u64 + a_bigint, the second a_bigint + an_u8 (and both set OutputType to be BigInt). You don't need to convert these types to BigInt before adding them! And if you want your method to handle any such type you just need an Add bound similar to the From bound in Frxstrem's answer. Of course if you want many such operations, From may end up more readable.
The From<T> trait (and the complementary Into<T> trait) is what is typically used to convert between types in Rust. In fact, the BigInt::from method comes from the From trait.
You can modify your short_name function into a generic function with a where clause to accept all types that BigInt can be converted from:
fn short_name<T>(n: T) -> BigInt // function with generic type T
where
BigInt: From<T>, // where BigInt implements the From<T> trait
{
BigInt::from(n)
}
In Rust, vectors are indexed using usize, so when writing
let my_vec: Vec<String> = vec!["Hello", "world"];
let index: u32 = 0;
println!("{}", my_vec[index]);
you get an error, as index is expected to be of type usize. I'm aware that this can be fixed by explicitly converting index to usize:
my_vec[index as usize]
but this is tedious to write. Ideally I'd simply overload the [] operator by implementing
impl<T> std::ops::Index<u32> for Vec<T> { ... }
but that's impossible as Rust prohibits this (as neither the trait nor struct are local). The only alternative that I can see is to create a wrapper class for Vec, but that would mean having to write lots of function wrappers as well. Is there any more elegant way to address this?
Without a clear use case it is difficult to recommend the best approach.
There are basically two questions here:
do you really need indexing?
do you really need to use u32 for indices?
When using functional programming style, indexing is generally unnecessary as you operate on iterators instead. In this case, the fact that Vec only implements Index for usize really does not matter.
If your algorithm really needs indexing, then why not use usize? There are many ways to convert from u32 to usize, converting at the last moment possible is one possibility, but there are other sites where you could do the conversion, and if you find a chokepoint (or create it) you can get away with only a handful of conversions.
At least, that's the YAGNI point of view.
Personally, as a type freak, I tend to wrap things around a lot. I just like to add semantic information, because let's face it Vec<i32> just doesn't mean anything.
Rust offers a simple way to create wrapper structures: struct MyType(WrappedType);. That's it.
Once you have your own type, adding indexing is easy. There are several ways to add other operations:
if only a few operations make sense, then adding explicitly is best.
if many operations are necessary, and you do not mind exposing the fact that underneath is a Vec<X>, then you can expose it:
by making it public: struct MyType(pub WrappedType);, users can then call .0 to access it.
by implementing AsRef and AsMut, or creating a getter.
by implementing Deref and DerefMut (which is implicit, make sure you really want to).
Of course, breaking encapsulation can be annoying later, as it also prevents the maintenance of invariants, so I would consider it a last ditch solution.
I prefer to store "references" to nodes as u32 rather than usize. So when traversing the graph I keep retrieving adjacent vertex "references", which I then use to look up the actual vertex object in the Vec object
So actually you don't want u32, because you will never do calculations on it, and u32 easily allows you to do math. You want an index-type that can just do indexing but whose values are immutable otherwise.
I suggest you implement something along the line of rustc_data_structures::indexed_vec::IndexVec.
This custom IndexVec type is not only generic over the element type, but also over the index type, and thus allows you to use a NodeId newtype wrapper around u32. You'll never accidentally use a non-id u32 to index, and you can use them just as easily as a u32. You don't even have to create any of these indices by calculating them from the vector length, instead the push method returns the index of the location where the element has just been inserted.
In C++, you have the ability to pass integrals inside templates
std::array<int, 3> arr; //fixed size array of 3
I know that Rust has built in support for this, but what if I wanted to create something like linear algebra vector library?
struct Vec<T, size: usize> {
data: [T; size],
}
type Vec3f = Vec<f32, 3>;
type Vec4f = Vec<f32, 4>;
This is currently what I do in D. I have heard that Rust now has Associated Constants.
I haven't used Rust in a long time but this doesn't seem to address this problem at all or have I missed something?
As far as I can see, associated constants are only available in traits and that would mean I would still have to create N vector types by hand.
No, associated constants don't help and aren't intended to. Associated anything are outputs while use cases such as the one in the question want inputs. One could in principle construct something out of type parameters and a trait with associated constants (at least, as soon as you can use associated constants of type parameters — sadly that doesn't work yet). But that has terrible ergonomics, not much better than existing hacks like typenum.
Integer type parameters are highly desired since, as you noticed, they enable numerous things that aren't really feasible in current Rust. People talk about this and plan for it but it's not there yet.
Integer type parameters are not supported as of now, however there's an RFC for that IIRC, and a long-standing discussion.
You could use typenum crate in the meanwhile.
Rust newbie here. What would be a good way to go about dynamically inferring the most probably type given a string? I am trying to code a function that given a string returns the most possible type but I have no idea where to start. In Python I would probably use a try-except block. This is what I would expect to have:
"4" -> u32 (or u64)
"askdjf" -> String
"3.2" -> f64
and so on? I know that some strings can be assigned to several possible types so the problem is not well defined but I am only interested in the general philosophy on how to solve the problem efficiently in rust.
There is a parse method on string slices (&str) that attempts to parse a string as a particular type. You'll have to know the specific types you're ready to handle, though. The parse method can return values of any type that implements FromStr.
fn main() {
if let Ok(i) = "1".parse::<u32>() {
println!("{}", i);
}
if let Ok(f) = "1.1".parse::<f64>() {
println!("{}", f);
}
}
Note that the ::<T> part is only necessary if the compiler is unable to infer what type you're trying to parse into (you'll get a compiler error in that case).
I am trying to code a function that given a string returns the most possible type but I have no idea where to start.
First of all: Rust is statically typed which means that a function returns one and only one type, so you can't just return different types, like in dynamically typed languages. However, there are ways to simulate dynamic typing -- namely two (that I can think of):
enum: If you have a fixed number of possible types, you could define an enum with one variant per type, like this:
enum DynType {
Integer(i64),
Float(f32),
String(String),
}
fn dyn_parse(s: &str) -> DynType {
...
}
You can read more on enums in this and the following Rust book chapter.
There is a trait in the standard library designed to simulate dynamic typing: Any. There is more information here. Your code could look like this:
fn dyn_parse(s: &str) -> Box<Any> {
...
}
You can't return trait objects directly, so you have to put it in a Box.
Keep in mind that both possibilities require the user of your function to do additional dispatch. Since Rust is statically typed, you can't do the things you are used to in a dynamically typed language.
Maybe you should try to solve your problems in a different way that makes more sense in the statically typed world.
About the implementation part: Like Francis Gagné said, there is parse which tries to parse a string as a type the programmer specifies. You could of course just chain those parse calls with different types and take the first one that succeeds. But this might not be what you want and maybe not the fastest implementation.
Of course you should first think of exact rules what string should parse as what type. After that you could, for example, build a finite state machine that detects the type of the string. Doing that properly could be a bit tricky though.