I'm trying to use a conditional compilation statement. Beyond defining a function that should only exist in a debug build, I want to define a set of variables/constants/types that only exist in the debug build.
#[cfg(debug)]
pub type A = B;
pub type B = W;
#[cfg(other_option)]
pub type A = Z;
pub type B = I;
let test = 23i32;
How many lines are actually "covered" by the conditional compile attribute in this case? Is it only one (what I would expect in this context)? Are there ways to ensure that a whole block of code (including variables, types and two functions) is covered by the condition?
You can use a module to group together everything that should exist for debug/release only, like this:
#[cfg(debug)]
mod example {
pub type A = i32;
pub type B = i64;
}
#[cfg(not(debug))]
mod example {
pub type A = u32;
pub type B = u64;
}
fn main() {
let x: example::A = example::A::max_value();
println!("{}", x);
}
Playground link (note that this will always print the not(debug) value because the playground doesn't define the debug feature, even in debug mode).
If debug is defined, this will print 2147483647 (the maximum value of an i32), otherwise it will print 4294967295 (the maximum value of a u32). Keep in mind that both modules must have definitions for each item, otherwise you'll hit a compile-time error.
If you've not read about Attributes, it might be a good idea to do so; make sure you know the difference between inner attributes (#![attribute]) and outer attributes (#[attribute]).
An #[attribute] only applies to the next item. Please see the Rust book.
Edit: I don't think it is currently possible to spread an attribute over an arbitrary number of declarations.
Additional, in-depth information on attributes and their application can be found at Rust reference.
Related
I'm writing my first rust program and as expected I'm having problems making the borrow checker happy. Here is what I'm trying to do:
I would like to have a function that allocates some array, stores the array in some global data structure, and returns a reference to it. Example:
static mut global_data = ...
fn f() -> &str {
let s = String::new();
global.my_string = s;
return &s;
};
Is there any way to make something like this work? If not, what is "the rust way"(tm) to get an array and a pointer into it?
Alternatively, is there any documentation I could read? The rust book is unfortunately very superficial on most topics.
There are a couple things wrong with your code:
Using global state is very unidiomatic in rust. It can be done in some specific scenarios, but it should never be a go to method. You cold try wrapping your state in Rc or Arc and share it this way in your program. If you also want to mutate this state (as you show in your example) you must to wrap it also in some kind of interior mutability type. So try Rc<RefCell<State>> if you want to use state in only one thread or Arc<Mutex<State>> if you want to use it from multiple different threads.
Accessing mutable static memory is unsafe. So even the following code won't compile:
static mut x: i32 = 0;
// neither of this lines work!
println!("{}", x);
x = 42;
You must use unsafe to access or modify any static mutable variables, because you must de facto prove to the compiler that you assure it that no data races (from accessing this data from different threads) will occur.
I can't be sure, since you didn't show what type is global_data, but I assume, that my_string is a field of type String. When you write
let s = String::new();
global.my_string = s;
You move ownership of that string to the global. You therefore cannot return (or even create) reference to it. You must do this though it's new owner. &global.my_string could work, but not if you do what I written in 1. You could try to return RefMut of MutexGuard, but that is probably not what you want.
Okay, just in case someone else is having the same question, the following code seems to work:
struct foo {
b : Option<Box<u32>>,
}
static mut global : foo = foo { b : None };
fn f<'a>() -> &'a u32 {
let b : Box<u32> = Box::new(5);
unsafe {
global.b = Some(b);
match &global.b {
None => panic!(""),
Some(a) => return &a,
}
}
}
At least it compiles. Hopefully it will also do the right thing when run.
I'm aware that this is not how you are supposed to do things in rust. But I'm currently trying to figure out how to implement various data structures from scratch, and the above is just a reduced example of one of the problems I encountered.
I am learning Rust and here is the sample from the book
use std::convert::TryInto;
fn main() {
let a: i32 = 10;
let b: u16 = 100;
let b_ = b.try_into()
.unwrap();
if a < b_ {
println!("Ten is less than one hundred.");
}
}
Author says b.try_into() converts b to i32. But where do we specify this in code? b_ is not given an explicit type, so why would a u16 get converted to i32 and not to a u32 or something else?
Thanks.
Rust has a quite smart compiler and it can look at nearby code to determine what type a variable should get. This is called type inference.
If you explicitly want to set the type that the .try_into() function should convert, you can put the type in the usual position.
let b_: i32 = b.try_into().unwrap();
You also need to remember that you cannot specify any type for conversion because they are manually implemented in the Rust standard library.
My guess is that the compiler looks at the bottom if statement and infers that b_ should be a i32 (So that it can perform the if check with a which it already knows is an i32).
I also tested that reversing the condition i.e if b_ > a causes a compile error. I guess it is because it wants to know what type b_ is before going for a
I want to write a macro_rules based macro that will be used to wrap a series of type aliases and struct definitions. I can match on "items" with $e:item, but this will match both aliases and structs. I would like to treat the two separately (I need to add some #[derive(...)] just on the structs). Do I have to imitate their syntax directly by matching on something like type $name:ident = $type:ty; or is there a better way? This route seems annoying for structs because of regular vs tuple like. If I also wanted to distinguish functions that would be really painful because they have a lot of syntactical variation.
I believe for that problem somewhat simple cases can be solved with macro_rules!, but that probably would be limited (you can't lookahead) and super error-prone. I only cover an example for types, I hope that would be convincing enough to avoid macro_rules!. Consider this simple macro:
macro_rules! traverse_types {
($(type $tp:ident = $alias:ident;)*) => {
$(type $tp = $alias;)*
}
}
traverse_types!(
type T = i32;
type Y = Result<i32, u64>;
);
That works fine for the trivial aliases. At some point you probably also would like to handle generic type aliases (i.e. in the form type R<Y> = ...). Ok, your might still rewrite the macro to the recursive form (and that already a non-trivial task) to handle all of cases. Then you figure out that generics can be complex (type-bounds, lifetime parameters, where-clause, default types, etc):
type W<A: Send + Sync> = Option<A>;
type X<A: Iterator<Item = usize>> where A: 'static = Option<A>;
type Y<'a, X, Y: for<'t> Trait<'t>> = Result<&'a X, Y>;
type Z<A, B = u64> = Result<A, B>;
Probably all of these cases still can be handled with a barely readable macro_rules!. Nevertheless it would be really hard to understand (even to the person who wrote it) what's going on. Besides, it is hard to support new syntax (e.g. impl-trait alias type T = impl K), you may even need to have a complete rewrite of the macro. And I only cover the type aliases part, there's more to handle for the structs.
My point is: one better avoid macro_rules! for that (and similar) problem(-s), procedural macros is a way much a better tool for that. It easier to read (and thus extend) and handles new syntax for free (if syn and quote crates are maintained). For the type alias this can be done as simple as:
extern crate proc_macro;
use proc_macro::TokenStream;
use syn::parse::{Parse, ParseStream};
struct TypeAliases {
aliases: Vec<syn::ItemType>,
}
impl Parse for TypeAliases {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut aliases = vec![];
while !input.is_empty() {
aliases.push(input.parse()?);
}
Ok(Self { aliases })
}
}
#[proc_macro]
pub fn traverse_types(token: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(token as TypeAliases);
// do smth with input here
// You may remove this binding by implementing a `Deref` or `quote::ToTokens` for `TypeAliases`
let aliases = input.aliases;
let gen = quote::quote! {
#(#aliases)*
};
TokenStream::from(gen)
}
For the struct parsing code is the same using ItemStruct type and also you need a lookahead to determine wether it's an type-alias or a struct, there's very similar example at syn for that.
I have the following simple program
fn main() {
let a = 10;
let b: i32;
let r: &i32;
b = a; // move?
r = &a; // borrow?
println!("{}", a);
println!("{}", b);
println!("{}", r);
println!("{}", &r);
println!("{}", *r);
}
The output is
10
10
10
10
10
The first print does not fail even when the value is moved. Is this because of primitive type or am I missing something?
The second print seems ok.
The third one prints a reference directly - shouldn't we get the memory address as this is a reference?
The fourth print is a reference to a reference, which should print a memory address, I think?
The fifth print seems reasonable as (I think) * is the value at operator that de-references the reference.
It seems I am not quite getting the whole thing.
Please explain in detail what's going on.
Related:
Move vs Copy in Rust
1, 2 => You are working with i32, which is Copy, so in practice b = a.clone()
3, 4, 5 => You're confused with the Deref trait. I find it easier to reason about ownership/borrowing than references in rust. r = &a means r borrows a so I can access its value later on, someone else will own it and take care of dropping it
Regarding 1: Yes, because it's a primitive variable, more specifically a type that implements the Copy trait. All those Copy-types work with copy semantics instead of move semantics.
Regarding 3: println! automatically dereferences it's arguments -- this is what the user wants in 99% of all cases.
Regarding 4: Again, automatically dereferences arguments... until it's a non-reference type.
The other answers are mostly right, but have some small errors.
1. i32 implements Copy, so when you assign it to a second variable binding, the first binding does not need to be invalidated. Any type that implements Copy will have this property.
3. You have asked to format the value with {} which corresponds to the Display trait. There is an implementation of this trait for references to types that implement Display:
impl<'a, T> Display for &'a T where T: Display + ?Sized {
fn fmt(&self, f: &mut Formatter) -> Result { Display::fmt(&**self, f) }
}
This simply delegates to the implementation of the referred-to type.
4. The same as #3 - a reference to a reference to a type that implements Display will just delegate twice. Deref does not come into play.
Here's the sneaky thing that no one else has mentioned. println! is a macro, which means it has more power than a regular function call. One of the things that it does is automatically take a reference to any arguments. That's what allows you to print out a value that doesn't implement Copy without losing ownership.
With this code:
let a = 10;
println!("{}", a);
The expanded version is actually something like this (slightly cleaned up):
let a = 10;
static __STATIC_FMTSTR: &'static [&'static str] = &["", "\n"];
::std::io::_print(::std::fmt::Arguments::new_v1(__STATIC_FMTSTR, &match (&a,) {
(__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
}));
Therefore, everything passed to println! is a reference. It wouldn't be very useful if references printed out memory addresses.
Besides the usefulness, Rust focuses more on value semantics as opposed to reference semantics. When you have values moving and changing addresses frequently, the location of the value isn't very consistent or useful.
See also
Auto-dereference when printing a pointer, or did I miss something?
Reference to a vector still prints as a vector?
I have the following line of code which I expect to just work:
const pi_n4th_root : f32 = Float::pi().powf(-1.0/4.0);
but it produces the following error:
f.rs:7:28: 7:54 error: the type of this value must be known in this context
f.rs:7 const pi_n4th_root : f32 = Float::pi().powf(-1.0/4.0);
^~~~~~~~~~~~~~~~~~~~~~~~~~
I tried to add every type annotation that I can:
const pi_n4th_root : f32 = (Float::pi() as f32).powf(-1.0/4.0 as f32) as f32;
but it still fails with the same error:
f.rs:7:30: 9:55 error: the type of this value must be known in this context
f.rs:7 const pi_m4th_root : f32 = (Float::pi::<f32>() as f32).powf(-1.0/4.0 as f32) as f32;
^~~~~~~~~~~~~~~~~~~~~~~~~
Seems that I need to specify somehow that Float::pi is called for the f32 type but how to do that?
Unfortunately, what you want to do won't work for two reasons.
First, you can't write anything like this:
const pi_n4th_root : f32 = Float::pi().powf(-1.0/4.0);
That is, you can't call any functions in constant definitions, because exact values of constants should be known to the compiler, and Rust does not have compile-time function evaluation yet.
Second, as UFCS is not yet implemented, you cannot invoke trait methods for some specific type directly. I'm not sure why Float::pi() as f32 does not work, but you can't specify desired type in paths too. The only way to do it would be writing a separate function:
#[inline]
pub fn pi<T: Float>() -> T { Float::pi() }
There are many such functions in Rust standard library. For Pi constant, however, there is a better way - you can use the constant of appropriate type directly:
use std::f32;
let pi = f32::consts::PI;
You can find a list of constants here and here (you can press [src] link if the page itself is empty, seems to be a bug in Rustdoc).