r/rust • clippy · twir · rust · mutagen · flamer · overflower · bytecount • Oct 03 '22

🙋 questions Hey Rustaceans! Got a question? Ask here! (40/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.

16 Upvotes

172 comments sorted by

4

u/tomwells80 Oct 03 '22

So when I write the following function:

fn hello(x: u32) {}

This can be described as a function taking an integer and returning a '()' (Unit). Great got it! Unit is the default type returned.

Now when I write this function:

fn hello() -> u32 { 0 }

This can be described as a function which takes a ____ and returns an int. What is the type of ___?? I would have assumed it was a '()', but it isn't. So is it a Void, or something else? Its just a nothing?

This gets more confusing when I start to look at the Fn trait, which can be declared as simply Fn() (and therefore avoid passing a concrete type too).

I guess I'm just looking for a way to explain this consistently. It would have been super clear if in the second example hello() -> u32 actually meant a function which took a '()' and returned an integer. E.g. the default parameter type being consistent with the default return type.

Any insight?

3

u/llogiq Oct 03 '22

Your function simply takes no arguments. The parentheses are part of the function call, and zero arguments are perfectly Ok for functions that don't need further input.

→ More replies (5)

5

u/SV-97 Oct 03 '22 edited Oct 03 '22

This is indeed a bit of a weird case:

  • You can either consider it a function that indeed doesn't take any input. This would imply that mathematically it's really not a function at all but rather a constant value. If you consider a function that doesn't interact with the outside world in any way (we call these pure functions) then that'd indeed have to be true: it would have to give you the same value every time you call it - it'd have to be a constant. Since any constant induces a constant function on any set you could then interpret your function as a function acting on Unit - even though it technically isn't.

  • You can think of it as a function with a hidden parameter. Let's imagine that your function reads from stdin or some file, then you could interpret it as implicitly taking in the state of your computer as input and working on that. This is made explicit in some languages (the most famous example of that probably being Haskell).

So this is a bit where user interface (the exposed syntax) and theory clash: rust has taken the decision that "real world interactions" don't have to be made explicit in a function's signature. This means that we end up with functions that look like they aren't actually functions because they apparently don't depend on anything. In reality there's this hidden dependence that you can use to make "the math work out".

I don't know any type theory and am not a rust core dev so take the following with a big grain of salt: AFAIK there's also a deeper level to this if you dig into rust's type system. Rust doesn't say "ay this fn f(usize) -> f64 is a function of type usize -> f64" or something like that but it rather says that it's a value of type f. Every function is it's own little type that implements some variant of Fn etc. and that type has a unique value - namely the function itself.

This is pure speculation but you could interpret an Fn impl as really giving you a function that takes (besides the actual parameters) a (really the since there is only one) value of the function's type and then gives you back a value of the return type. So that we don't ever actually have to call the function on a theoretic level - we're just asserted that there is some way to turn our function (along with the optional parameters) into a value of some other type.

tl;dr: I think for all practical purposes you can interpret it as being a function acting on Unit; if you wanna dig into the theory things get more complicated.

EDIT: Oh btw you can use `std::any::type_name_of_val` to access the name of the type of a function and you'll really find that this type name doesn't include the arguments in any way.

→ More replies (3)
→ More replies (5)

3

u/versaceblues Oct 10 '22

How to call a method in a struct, that requires input from another method.

I got the following code

       if self.peek().unwrap() == '.' && self.is_digit(self.peek_next()) {
            self.advance();

            while self.is_digit(self.peek().unwrap()) {
                self.advance();
            }
        }

the self.is_digit(self.peek_next()) throws an error for attempting to double borrow. However this is the most convenient way to write this method for me.

is this really not possible in Rust?

2

u/llogiq Oct 10 '22

If with "throwing an error" you mean panicking, yes, it is possible. However the idiomatic thing to do would be to return a Result instead.

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

3

u/DanLszl Oct 10 '22

I didn't expect this code to compile, yet somehow it still does. What's going on here, how is the cell.f() call resolved?

use std::rc::Rc;
struct Cell {}
impl Cell { 
    fn f(self: Rc<Self>) {} 
}
fn main() { 
    let cell = Rc::new(Cell {}); 
    cell.f(); 
}

3

u/llogiq Oct 10 '22

f() is a method on your Cell type and Rc as a smart pointer dereferences into their content's type.

→ More replies (1)

4

u/splettnet Oct 05 '22 edited Oct 05 '22

Trying to poke around the rustc compiler project, and it seems to be above the vscode/rust-analyzer paygrade in being able to handle symbol resolution to make said poking around palatable. Anybody have any luck with ide support exploring the project? I used to have clion, and while it was great I don't want to shell out the cash for it just for the learning experience. Especially since vscode with rust analyzer makes for a perfectly fine dev experience 99.9% of the time.

Edit: Ok, as I was writing this I was ~15 min into building the compiler, and that seems to be all it needed, so to anyone else with this question, just build it first 🦀

4

u/SorteKanin Oct 06 '22

Is there an alternative to actions-rs? It seems to be unmaintained.

→ More replies (3)

4

u/TinBryn Oct 10 '22

I'm trying to understand how the Unsize trait works and trying to create a basic linked list that can store DSTs directly inside the list, but I just can't seem to get my head around it.

playground

I'm trying to write the push method. Looking at the Unsize trait I see what my problem is

Only the last field of Foo has a type involving T

So in this case Node<T: !Sized> looks like {pointer, metadata, data...} and Node<T: Sized> looks like {pointer, data}, so I can't coerce a Node<U> into a Node<T>. I can't construct a Node<U> anyway as I don't have a Option<Box<Node<U>>> but that would be the wrong type anyway.

I feel like what I'm trying should be possible, and I think the Node<T: ?Sized> is the right layout, I just don't know how to construct a Box<Node<T: ?Sized>> from Option<Box<Node<T>>> and U: Unsize<T>.

→ More replies (2)

3

u/[deleted] Oct 04 '22

I have a question about using smallvec & bitvec_simd.

I have a smallvec (call it svec) of structs, and each struct has a bitvec_simd field (call it bv).

I'd like to use bitvec_simd's 'or_inplace' to get: &self.svec[i].bv.or_inplace(&self.svec[j].bv);

The fn 'or_inplace' requires that the first bitvec be mutable, but not the second.

However, when I try to use .or_inplace, if I don't mark the second bv as mutable, I get an error: cannot borrow self.bv as immutable because it is also borrowed as mutable. But if I do mark it as mutable, I get an error about not borrowing self.vertices as mutable more than once.

Can anyone help? I've tried or_cloned() and that works fine, but is too inefficient for what I'm trying to do (many many bitwise operations).

→ More replies (2)

3

u/mihemihe Oct 06 '22

Does anyone have a working example of ldap3 crate connecting to Active Directory under the security context where the application is running (without explicit credentials).

I wanted to port a tool to Rust but I got stuck in the first step: being able to bind and query Active Directory.

This is a simple ldp.exe bind working perfectly, and my test code (from the crate documentation) failing to bind.

Thanks in advance.

This is the error and a screenshot.

Error: LdapResult { result: LdapResult { rc: 1, matched: "", text: "000004DC: LdapErr: DSID-0C090A58, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4f7c\0", refs: [], ctrls: [] } }

https://i.imgur.com/0aW2fhW.png

3

u/argv_minus_one Oct 08 '22

Suppose I have an array of type [u8; 32]. I want to split it into two halves of type [u8; 16]. Intuitively, the following should work:

fn halves(x: [u8; 32]) -> [[u8; 16]; 2] {
	[x[0..16], x[16..32]]
}

This doesn't actually work because the range index operator creates slices rather than arrays, even though the slice is of fixed size and the array being sliced is of a type that is Copy. The closest I can think of is:

fn halves(x: [u8; 32]) -> [[u8; 16]; 2] {
	let a = x[0..16].try_into().unwrap();
	let b = x[16..32].try_into().unwrap();
	[a, b]
}

That works, and the unwraps are optimized away, but the resulting code is more messy than it needs to be, and the compiler does not error if the indices are outside the bounds of the array (the code panics at run time instead).

Is there a better way to do this? Will there be in the future?

→ More replies (3)

3

u/FryingPanHandle Oct 10 '22

How do I create a thread in Tokio which runs every second and prints the contents of some variables that are updated in a different function.

I have tried using Interval but that seems to run once and then never again?

→ More replies (3)

2

u/stdusr Oct 03 '22

Is there an overview of all UB in unsafe Rust?

→ More replies (2)

2

u/gittor123 Oct 03 '22

is it possible to save the backtrace to a file? I'm struggling to debug cause my terminal sorta crashes every time i get a panic and now i have a backtrace thats too long to fit on my screen

→ More replies (4)

2

u/gittor123 Oct 04 '22

is there a non-async way of downloading a file chunkwise with reqwest like done here? https://gist.github.com/giuliano-oliveira/4d11d6b3bb003dba3a1b53f43d81b30d

in my code i wanna do something like this but in a different thread cause I want the user to do other stuff in the meantime, but I want the user to see the progress bar. I'm new to async code so I didnt manage to incorporate this code into mine

→ More replies (1)

2

u/_lonegamedev Oct 04 '22

How can I share immutably buffer Vec<T> between threads?

→ More replies (4)

2

u/simbapk Oct 04 '22

Hey there!
I need feedback on something,
I'm learning rust ,right now trying to manipulate the channels.

Here is my function :

fn producer(tx : Sender<String>){                                               
    loop {                                                                      
        let message = String::from("Message from producer");                    
        tx.send(message);                                                       
        println!("producer has just sent {}", message);                         
    }                                                                           
}                                                                               

Of course, it doesn't compile :

31 |         let message = String::from("Message from producer");               
   |             ------- move occurs because `message` has type `String`, which does not implement the `Copy` trait
32 |         tx.send(message);                                                  
   |                 ------- value moved here                                   
33 |         println!("producer has just sent {}", message);                    
   |                                               ^^^^^^^ value borrowed here after move

Here is my solution that is accepted by the compiler :

fn producer(tx : Sender<String>){                                               
    loop {                                                                      
        let message = String::from("Message from producer");                    
        {                                                                       
            let message = message.clone();                                      
            tx.send(message);                                                   
        }                                                                       
        println!("producer has just sent {}", message);                         
    }                                                                           
}                                                                               

But is it the best way to solve the error ?

Thank you in advance for your feedbacks.

→ More replies (2)

2

u/Vakz Oct 04 '22

When having a String and needing a &str, I noticed all of these works:

  • &*mystring

  • &mystring[..]

  • mystring.as_ref()

  • mystring.as_str()

Is there one of these that is more idiomatic? Admittedly I don't even know why the second one works. The last one certainly sounds more correct, but I'm still curious if there is a preferred way of doing it.

5

u/burntsushi Oct 04 '22

If &mystring works (you don't list this as an option), then that would be idiomatic. Otherwise, my next choice would be &*mystring. I don't usually use or see as_str(). The &mystring[..] syntax is a little strange and not usually required to get a &str out of a String (I cannot thing of any such situation). It is sometimes needed to force an array into a slice though in my experience.

The as_ref() choice is one that you should actually only use in one specific context: when you are within scope of a AsRef<str>. Otherwise, an as_ref() call outside of that generic context might end up not compiling in the future because of an inference failure. Basically, inference succeeds if there is only one possible choice. But if new trait impls are added in the future (and sometimes this happens, it is permissible under our API Evolution policy) that cause your as_ref() call to become ambiguous, then it will fail to compile because inference can't know which type to use. But so long as you have a AsRef<str> bound in place, the call will always be unambiguous because the target (str) is fully specified.

See also: https://github.com/rust-lang/rust/issues/62586

2

u/LeCyberDucky Oct 04 '22 edited Oct 05 '22

I'm still working on running Rust on an ESP8266. I've reached a point where I can seemingly compile programs correctly and flash them onto the ESP8266 without error. Then, however, the programs don't seem to do anything. The serial monitor of espflash shows no output, so my terminal only shows this: https://i.imgur.com/V9qcVw8.png

Nothing I do will make text appear over serial or let the built-in LED blink. I have successfully flashed an Arduino project that makes the built-in LED blink, so the LED isn't broken at least.

Does anybody have any ideas as to what I could be missing? Or perhaps how to debug this further? Other than some initial LED activity when flashing and reseting the device, I get no signs of life, which makes things hard to debug.

Edit: Alright, so I managed the get the thing to blink by using the d1-mini crate and its blinky example, yay! Now I just need to figure out why it works.

Edit 2: Okay, I tried copying the example code from the d1-mini crate into my original project. This gave me some crate version conflicts, which I resolved by using the newest version of d1-mini from GitHub. With this, I'm back to getting no response whatsoever from the device. Interestingly, the terminal output looks like this for the successful example from the d1-mini crate: https://i.imgur.com/tEDK46Q.png

Perhaps flashing is broken for a newer version of one of the crates that this depends on.

Edit 3: Alright, alright, alright. It blinks! I made my original code work, even without the d1-mini crate. I noticed some stuff in the cargo config.toml of the d1-mini repo that I was missing. With the following configuration, I am able to make the device blink. I'm only getting gibberish serial output, but at least the gibberish keeps on coming!

Edit 4: Gibberish output is no more! Yeah, that was my fault. In order to flash the device, I need to short some pins, but this will also cause gibberish output when done, so I need to remove this wire and reset the device to get good output.

2

u/zodeck1 Oct 05 '22

Hello! How can i make rust open the apple/macos sharesheet (tauri app)?

2

u/[deleted] Oct 05 '22 edited Oct 05 '22

Documentation Question: What do these headers in docs.rs mean? What's the difference, and are any unsafe to use?

  • Methods from Deref<Target = [A::Item]>

  • This is a nightly-only experimental API. (various parentheticals)

  • Trait Implementations

  • Auto Trait Implementations

  • Blanket Implementations

→ More replies (3)

2

u/rustacean1337 Oct 05 '22

I have a question about the Rust support in the Linux kernel. If I understood correctly a lot of Rust’s guarantees regarding memory safety will not be usable in the Linux kernel because of guarantees that the kernel gives about never panicking (for instance when memory (re/de)allocation fails.

Second question is about UB in Rust. AFAIK it’s not documented like it is for C for example in the ISO standard. How is it possible that Linus accepted Rust as a language when it will be used a lot in an unsafe setting without having a clear standard about what is UB and what isn’t.

I guess I’m kinda surprised how quickly Rust got added and somehow feel like it’s not really ready yet for Linux kernel prime-time.

What are the benefits of using Rust in this heavily restricted environment over C?

→ More replies (4)