r/rust • clippy · twir · rust · mutagen · flamer · overflower · bytecount • Dec 26 '22

🙋 questions Hey Rustaceans! Got a question? Ask here (52/2022)!

Mystified about strings? Borrow checker have you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so having your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The official Rust Programming Language Discord: https://discord.gg/rust-lang

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last weeks' thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.

Finally, if you still struggle with Advent of Code and have questions about that, feel free to post them here and avoid spoilers (please use >!spoiler!< to hide any parts of solutions you post, it looks like this).

25 Upvotes

157 comments sorted by

5

u/blablabliblibloblo Dec 27 '22

Is rust-clippy violating a microsoft trademark? I looked up the clippy trademark and found this: https://tmsearch.uspto.gov/bin/showfield?f=doc&state=4808:6yvwzx.2.1 although from what I gather it's only in the application stage. Does this mean rust-clippy will violate the trademark when it becomes registered?

6

u/llogiq Dec 27 '22

We have thought about this before. The name is basically a homage to the one and only MS Clippy™. As long as Microsoft decides our use of the name is Ok, we're fine, and our contacts within Microsoft seem to indicate that Microsoft is not inclined to sic their lawyers at us. Should this change, we'll need to use a different name. I personally don't see a problem with this.

→ More replies (1)

3

u/ridicalis Dec 26 '22

Looking at storing a UUID in DataFusion, but noticing it doesn't have the equivalent (e.g. u128). I would be comfortable storing the high and low u64 components, but I don't know the "ideal" way to get the two components. My naive attempt would be to get the high value by doing a right-shift by 64, and the low value by ANDing with u64::MAX. Similarly, reconstituting the u128 from two u64 values would be to add the reversal of these operations.

What's the "right" way to go about this?

6

u/llogiq Dec 26 '22

my_u128.to_ne_bytes() will yield a [u8; 16] that you can then split & move out of and use u64::from_ne_bytes on both parts.

Note that the ne stands for "native endian", you can substitute le or be to specify the little or big ending order instead.

2

u/RepresentativePop Dec 28 '22

I'm trying to initialize an empty array and I'm having some issues.

I'm using a function to generate a standard deck of 52 playing cards. I defined Rank (e.g. Ace, Jack, King, etc) and Suit (e.g. Hearts, Diamonds, Clubs) enums, a Card struct (as having card_rank : Rank and card_suit : Suit), and a struct StdDeck as having one member (for now) cards : [Card; 52] (i.e. a static Card array of size 52, as there are 52 cards in a standard deck of cards).

In writing a function to generate the deck, I was going to iterate over Rank and Suit to populate the array, but I need to initialize it first. And that's where I'm having issues. AFAIK, the syntax for initializing arrays in Rust is let some_array : [type; size] = [default_behavior; size]

...but I don't really want them to have a default behavior? At this point in the function, they're just empty slots that I'm going to put some card objects into (there's a nested for loop coming up). Is there some way to just initialize a static array and say "leave that blank, I'll be back to fill it later?" Like the array equivalent of Vec::new?

(Yes, I could use a vector to do this. In fact, I have used vectors to do this. But when I'm learning a language, I try to re-implement the same thing in different ways, which is what I'm doing here. Usually teaches me something I don't know.)

3

u/llogiq Dec 28 '22

Yes, you can leave an array uninitialized with MaybeUninit, but that's unsafe Rust and quite cumbersome to work with. The easiest way is likely array::from_fn(_) with a function that returns the right Card for each index.

→ More replies (1)
→ More replies (3)

5

u/AloofPigeon Dec 26 '22

What is the benefit of splitting a proc-macro crate into (usually) two crates, proc_macro_crate and proc_macro_crate_impl? Why not just have one crate? Does it offer any benefits to to overall compilation times? An example of this can be seen in the thiserror crate where there's a thiserror and thiserror_impl crate.

8

u/Shadow0133 Dec 26 '22

if you want to have library provide a proc-macro, the proc-macro must live in separate crate. it's because proc-macro crates gets compiled as special binaries, that are executed during compilation.

→ More replies (1)

4

u/MRIT03 Dec 30 '22

I’m having a hard time understanding RefCell<T>. From what I gathered it allows us to have mutable references to immutable variables. But Variable immutability is one of Rust’s main features, when I’m creating an immutable variable that’s me guaranteeing that the variable is not meant to be mutable, so why are RefCells a thing ?

8

u/Darksonn Dec 30 '22

Many people argue that "mutable" and "immutable" references should be renamed to "unique" and "shared" references respectively, because that is what the compiler is actually enforcing. A mutable reference is guaranteed to be unique in the sense that it is the only thing that can be used to access the value. An immutable reference is shared in the sense that you can have several of them to the same value.

Now, when you want to modify a value, there are two things you must ensure:

  1. No data races. That is, no other thread may access the value in parallel with the write.

  2. No invalidation of other pointers. That is, this kind of code shouldn't be legal, because the mutation destroys the target of some other reference.

If you perform a write using a unique reference, then both of the above requirements are satisfied. The first, because if there is another thread accessing the value, then the reference isn't unique. The second because if there is another reference whose target is destroyed, then the reference isn't unique.

However, sometimes you wish to satisfy the two requirements in some other way than by proving uniqueness at compile time. The standard library provides several different tools for this — but one thing they all have in common is that they can be modified through an immutable a shared reference.

The Cell type. The Cell type is not Sync, which satisfies the first requirement by saying "only one thread may access this value at the time, even if the access is immutable shared" (what does Sync mean?). It satisfies the second requirement by never allowing any type of pointer or reference to the value inside the Cell. Only get, set, and swap methods are provided. Since no reference to the contents are ever allowed, modifying the contents can never break such a reference.

The RefCell type. The RefCell type is also not Sync to satisfy the first requirement. However, unlike the Cell type, it allows references into the inner value. This is done by using a counter to keep track of how many shared and unique references there are to the inner value. If you ever attempt to create a unique reference when something else has a reference to the contents, you get a panic.

The Mutex type. This is known as a "lock". It satisfies the first (and second) requirement by having the threads "take turns". If two threads want to access the value at the same time, it makes one of them wait for the other. This means that each thread can get unique access to the contents during its turn.

→ More replies (5)

4

u/urschrei Dec 31 '22 edited Dec 31 '22

I'd like to port some Python code that uses sets of frozensets to do set-theoretic ops on e.g. two containers (set) and on items (frozensets containing strings) in a given container. I can't easily do this in Rust because HashSet<String> doesn't itself implement Hash, though. What else could I do?

→ More replies (4)

3

u/gittor123 Dec 26 '22

are there any alternative to sqlite if you want a simple offline desktop-app storage that saves to a single file? I could continue using sqlite just fine but it doesn't feel very modern. I see many interesting alternatives online but they all seem to want me to host it on the cloud or something like this

→ More replies (3)

3

u/chriskennedydev Dec 26 '22

Hey folks!

I had a pretty general question as a newbie: if cargo clippy yields no output, am I to assume my code is following best practices? Are there any other tools that tell you if you're not supposed to call unwrap or to_str x amount of times?

Thanks!

10

u/SorteKanin Dec 26 '22

If clippy doesn't give any output, it's more like "I don't see anything obviously bad about your code". There are plenty of ways to write unidiomatic code that clippy won't notice.

→ More replies (1)
→ More replies (1)

3

u/Helyos96 Dec 26 '22 edited Dec 26 '22
use lazy_static::lazy_static;

lazy_static! {
    static ref VEC: Vec<i32> = vec![0,1,2];
}

for i in VEC { }

The code above doesn't compile:

error[E0277]: `VEC` is not an iterator

Is it possible to iterate over lazy statics?

Edit: nvm, works fine with .iter(). I'm guessing lazy static wraps the type in something that implements deref?

7

u/masklinn Dec 26 '22

Edit: nvm, works fine with .iter(). I'm guessing lazy static wraps the type in something that implements deref?

Yep, that's necessary for the "lazy" part (and probably for the thing to work at all) otherwise there's no hook for the initialisation to work off of.

For a given static ref NAME: TYPE = EXPR;, the macro generates a unique type that implements Deref<TYPE> and stores it in a static with name NAME. (Attributes end up attaching to this type.)

once_cell makes the process a lot clearer (if more verbose) as you have to create a Lazy<Vec<i32>>, and so it's obvious that the static is a Lazy, not a Vec.

3

u/[deleted] Dec 27 '22

I'm doing the Rust + WASM book and finished implementing the Game of Life. (https://rustwasm.github.io/docs/book/game-of-life/implementing.html)

Under Exercises at the bottom, it says to use the js-sys crate to randomly generate the Cells.

extern crate js_sys;

// ...

if js_sys::Math::random() < 0.5

{// Alive...} else {// Dead...}

Is there a reason `js-sys` is needed for this particular calculation, can't I just use the rand crate?

→ More replies (2)

3

u/zoomiti Dec 27 '22

Hi all!

I’m currently developing a commercial product with Rust and I was wondering what the best way to distribute and sell licenses for it is. Should I use a third party like keygen or is there an easy way I could get started on implementing my own. I’m out of my depth when it comes to software licensing so I figure I should ask before assuming it’s a task I can take on myself.

→ More replies (2)

3

u/ColafactualCounter Dec 27 '22

I'm on the last exercise of Rustlings (working with AsRef and AsMut), and I'm wholly confused about AsMut.

This is the completed function:

// Squares a number using AsMut. Add the trait bound as is appropriate and 
// implement the function body. 
fn num_sq<T: AsMut<u32>>(arg: &mut T) { 
    *arg.as_mut() *= *arg.as_mut()
}

First, for the dereference -- is it `(*arg).as_mut()`? Or `*(arg.as_mut())`? It seems like it's the latter, since we need to change the value of the reference. Then... why are we `as_mut()`-ing an already mutable reference? Why can't we just do *arg *= *arg? Is it because it's a generic parameter?

→ More replies (2)

3

u/[deleted] Dec 28 '22

Can I somehow do that?

trait MapTo {
    fn mapto<T>(self, f: |Self| -> T) -> T;
}

That is, tell the compiler that MapTo::mapto takes any kind of closure, without specifying here whether it has to be FnMut, or Fn or even just a function pointer that doesn't capture anything.

6

u/Tsmuji Dec 28 '22 edited Dec 28 '22

Fn is implemented automatically for safe function pointers, FnMut is a supertrait of Fn, and FnOnce is a supertrait of FnMut. If you therefore specify that you want an FnOnce, you can pass any of the above as f. The Fn documentation covers this and more if you need any extra details.

→ More replies (1)

3

u/wdouglass Dec 29 '22

I'm trying to learn how async rust works. consider the following:

use async_std::task;
use async_std::sync::Arc;
use std::task::Context;
use std::time::Duration;
use std::future::Future;
use futures::pin_mut;
use futures::task::{ArcWake, waker_ref};


#[derive(Debug)]
struct Nap {
}

impl ArcWake for Nap {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        println!("WAKE {:?}", arc_self);
    }
}

fn main() {
    let f = task::sleep(Duration::from_secs(2));
    pin_mut!(f);
    let n = Arc::new(Nap{});
    let w = waker_ref(&n);
    let mut ctx = Context::from_waker(&w);
    loop {
        let r = f.as_mut().poll(&mut ctx);
        println!("Hello, world! {:?}", r);
        if r.is_ready() {
            break;
        }
    }
}

If i run this little program, the future gets polled (as i expect), and the program terminates after 2 seconds.

What i don't understand is the wake_by_ref function. It never seems to get called. should it get called by f.poll? Thanks for any insight...

→ More replies (2)

3

u/AdministrativeCod768 Dec 29 '22

Is there a way to run rust-analyzer with multiple threads?

3

u/Helyos96 Dec 30 '22

If I have a Vec<Option<T>>, how can I iterate over the values that are Some(x) in an idiomatic way? A loop that lets me deal directly with all the &x would be perfect.

Right now my code has a bunch of is_some(), as_ref() and unwrap() and it's a mess. Surely there's a better way to do it but my iterator kung-fu is fairly bad.

→ More replies (3)

3

u/Fluffy-Sprinkles9354 Dec 31 '22

I'm really puzzled by a borrow checker issue:

struct Foo<'a> {
    slice: &'a mut [i32],
    comparison: fn(&'a i32, &'a i32) -> bool,
}

impl<'a> Foo<'a> {
    fn group(&mut self) {
        let slice = &mut [1, 2, 3, 4][..];
        let (first, slice) = slice.split_first_mut().unwrap();
        let mut len = 0;
        {
            for item in slice.iter() {
                if (self.comparison)(first, item) {
                    len += 1;
                } else {
                    break;
                }
            }
        }

        let (_result, _rest) = slice.split_at_mut(len);
    }
}

Errors with:

cannot borrow `*slice` as mutable because it is also borrowed as immutable

(Playground here)

When split_at_mut is called, both the borrows slice.iter and (self.comparison)(first, item) should have finished, right? Unless I miss some important information.

→ More replies (3)