I read this docs and stumbled on this line.
let an_integer = 5i32; // Suffix annotation
What is this mean? I am assuming that it have 5 as value and i32 as integer type. Is that correct?
Yes, that's correct. When you write the literal 5 in a program, it could be interpreted as a variety of types. (A literal is a value, such as 5, which is written directly into the source code instead of being computed.) If we want to express that a literal is of a certain type, we can append ("suffix") the type to it to make it explicit, as in 5i32.
This is only done with certain built-in types, such as integers and floating-point numbers, but it can come in handy in some cases. For example, the following is not valid:
fn main() {
println!("{}", 1 << 32);
}
That's because if you specify no type at all for an integer, it defaults to i32. Since it's not valid to shift a 32-bit integer by 32 bits, Rust produces an error.
However, we can write this and it will work:
fn main() {
println!("{}", 1u64 << 32);
}
That's because now the integer is a u64 and it's in range.
Related
In https://doc.rust-lang.org/book/primitive-types.html#numeric-types, it said that in
let x = 42; // x has type i32
That means x has the type i32 as default.
But in http://rustbyexample.com/cast/literals.html, it says that
Unsuffixed literal, their types depend on how they are used
I know I can't use i32 to index the vector, but the following code works:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let j = 1; // j has default type i32? or it has type when it is first used?
// And what is the type of 1?
println!("{}", v[1]); // is 1 a usize?
println!("{}", v[j]);
}
So, what is the type of a literal integral value?
From the language reference:
The type of an unsuffixed integer literal is determined by type
inference:
If an integer type can be uniquely determined from the surrounding program context, the unsuffixed integer literal has that type.
If the program context under-constrains the type, it defaults to the signed 32-bit integer i32.
If the program context over-constrains the type, it is considered a static type error.
On the line
println!("{}", v[1]); // is 1 a usize?
the surrounding program context requires 1 to be an usize (because that's what the [] operator needs), so yes, here 1 will have the type usize.
I am trying to parse a single char variable into ASCII value, but all the time I am getting an error.
Basing on answer of hansaplast from this post Parsing a char to u32 I thought this code should work:
let char_variable = 'a';
let shoud_be_u32_varaible = a.to_digit(10).unwrap();
But this code will always throw this error:
thread 'main' panicked at 'called Option::unwrap() on a None value'
For this, code example (example provided in answer of hansaplast):
let a = "29";
for c in a.chars() {
println!("{:?}", c.to_digit(10));
}
This .to_digit() method will work.
In both cases I am using on .to_digit(10) on variables which are type of char, but for my example this code throws an error and for the code from hansaplast this works. Can someone explain to me what is the difference between those examples and what I am doing wrong because now I am super confused?
Both examples can be found there: Rust playground example
Is using casting in this case will be ok?
let c = 'a';
let u = c as u32 - 48;
If not, can you tell me, what is recommended of doing this?
Okay, I think you are confusing type casting and integer parsing.
to_digit is an integer parsing method. It takes the character and given a radix determines its value in that base. So 5 in base 10 is 5 and is stored as 00000101. 11 in base 15 is stored in memory as 00010000.
Type casting of primitives in rust like 'c' as u32 is probably more what you are after. It's distinct from integer parsing in the sense that you don't care about the "meaning" of the number what you care about is the value of the bits that represent it in memory. This means that the character 'c' is stored as 1100011 (99).
If you only care about ascii characters you should also check char.is_ascii() before doing your conversion. That way you can store your results in a u8 instead of a u32
fn print_ascii_values_of_characters(string: &str) {
for c in string.chars() {
if c.is_ascii() {
println!("{:b}", c as u8) // :b prints the binary representation
}
}
}
I'd like to define a function that can return a number whose type is specified when the function is called. The function takes a buffer (Vec<u8>) and returns numeric value, e.g.
let byte = buf_to_num<u8>(&buf);
let integer = buf_to_num<u32>(&buf);
The buffer contains an ASCII string that represents a number, e.g. b"827", where each byte is the ASCII code of a digit.
This is my non-working code:
extern crate num;
use num::Integer;
use std::ops::{MulAssign, AddAssign};
fn buf_to_num<T: Integer + MulAssign + AddAssign>(buf: &Vec::<u8>) -> T {
let mut result : T;
for byte in buf {
result *= 10;
result += (byte - b'0');
}
result
}
I get mismatched type errors for both the addition and the multiplication lines (expected type T, found u32). So I guess my problem is how to tell the type system that T can be expressed in terms of a literal 10 or in terms of the result of (byte - b'0')?
Welcome to the joys of having to specify every single operation you're using as a generic. It's a pain, but it is worth.
You have two problems:
result *= 10; without a corresponding From<_> definition. This is because, when you specify "10", there is no way for the compiler to know what "10" as a T means - it knows primitive types, and any conversion you defined by implementing From<_> traits
You're mixing up two operations - coercion from a vector of characters to an integer, and your operation.
We need to make two assumptions for this:
We will require From<u32> so we can cap our numbers to u32
We will also clarify your logic and convert each u8 to char so we can use to_digit() to convert that to u32, before making use of From<u32> to get a T.
use std::ops::{MulAssign, AddAssign};
fn parse_to_i<T: From<u32> + MulAssign + AddAssign>(buf: &[u8]) -> T {
let mut buffer:T = (0 as u32).into();
for o in buf {
buffer *= 10.into();
buffer += (*o as char).to_digit(10).unwrap_or(0).into();
}
buffer
}
You can convince yourself of its behavior on the playground
The multiplication is resolved by force-casting the constant as u8, which makes it benefit from our requirement of From<u8> for T and allows the rust compiler to know we're not doing silly stuff.
The final change is to set result to have a default value of 0.
Let me know if this makes sense to you (or if it doesn't), and I'll be glad to elaborate further if there is a problem :-)
let hex = "100000000000000000".as_bytes().to_hex();
// hex == "313030303030303030303030303030303030"
println!("{:x}", 100000000000000000000000u64);
// literal out of range for u64
How can I got that value?
In Python, I would just call hex(100000000000000000000000) and I get '0x152d02c7e14af6800000'.
to_hex() comes from the hex crate.
One needs to be aware of the range of representable values for different numeric types in Rust. In this particular case, the value exceeds the limits of an u64, but the u128 type accommodates the value. The following code outputs the same value as the example in Python:
fn main() {
let my_string = "100000000000000000000000".to_string(); // `parse()` works with `&str` and `String`!
let my_int = my_string.parse::<u128>().unwrap();
let my_hex = format!("{:X}", my_int);
println!("{}", my_hex);
}
Checked with the Rust Playground:
152D02C7E14AF6800000
An explicit usage of arbitrary precision arithmetic is required in the general case. A few suggestions from What's the best crate for arbitrary precision arithmetic in Rust? on Reddit:
num_bigint works on stable and does not have unsafe code.
ramp uses unsafe and does not work on stable Rust, but it is faster.
rust-gmp and rug bind to the state-of-the-art bigint implementation in C (GMP). They are the fastest and have the most features. You probably want to use one of those.
In Python, this would be final_char = mystring[-1]. How can I do the same in Rust?
I have tried
mystring[mystring.len() - 1]
but I get the error the type 'str' cannot be indexed by 'usize'
That is how you get the last char (which may not be what you think of as a "character"):
mystring.chars().last().unwrap();
Use unwrap only if you are sure that there is at least one char in your string.
Warning: About the general case (do the same thing as mystring[-n] in Python): UTF-8 strings are not to be used through indexing, because indexing is not a O(1) operation (a string in Rust is not an array). Please read this for more information.
However, if you want to index from the end like in Python, you must do this in Rust:
mystring.chars().rev().nth(n - 1) // Python: mystring[-n]
and check if there is such a character.
If you miss the simplicity of Python syntax, you can write your own extension:
trait StrExt {
fn from_end(&self, n: usize) -> char;
}
impl<'a> StrExt for &'a str {
fn from_end(&self, n: usize) -> char {
self.chars().rev().nth(n).expect("Index out of range in 'from_end'")
}
}
fn main() {
println!("{}", "foobar".from_end(2)) // prints 'b'
}
One option is to use slices. Here's an example:
let len = my_str.len();
let final_str = &my_str[len-1..];
This returns a string slice from position len-1 through the end of the string. That is to say, the last byte of your string. If your string consists of only ASCII values, then you'll get the final character of your string.
The reason why this only works with ASCII values is because they only ever require one byte of storage. Anything else, and Rust is likely to panic at runtime. This is what happens when you try to slice out one byte from a 2-byte character.
For a more detailed explanation, please see the strings section of the Rust book.
As #Boiethios mentioned
let last_ch = mystring.chars().last().unwrap();
Or
let last_ch = codes.chars().rev().nth(0).unwrap();
I would rather have (how hard is that!?)
let last_ch = codes.chars(-1); // Not implemented as rustc 1.56.1