[HN Gopher] A half-hour to learn Rust
___________________________________________________________________
A half-hour to learn Rust
Author : selvan
Score : 1037 points
Date : 2021-01-02 05:50 UTC (17 hours ago)
(HTM) web link (fasterthanli.me)
(TXT) w3m dump (fasterthanli.me)
| stonecharioteer wrote:
| I spent a few hours typing this entire article into an editor
| just to build muscle memory and I'm amazed. It's exactly the sort
| of article I needed to learn Rust. I've since thanked Amos on
| Twitter and I've forwarded links to his blog to a lot of people.
| This is a great article and does a good job clarifying things to
| a newcomer.
| mlthoughts2018 wrote:
| So Rust is Scala but with some extra complicated additional
| syntax around borrowing references and generic lifetime
| constraints.
| steveklabnik wrote:
| Scala has many features Rust does not have as well.
| mlthoughts2018 wrote:
| Yeah, when reading this I was wondering if Rust has sealed
| traits like Scala, and also structural typing.
|
| The extreme degree of shared syntax and shared semantics with
| Scala was really surprising to me.
| steveklabnik wrote:
| Rust does not have sealed traits, though you can sorta
| contort the privacy system to do similar things if you
| want. We also do not have structural typing. (Generally;
| tuples are structurally typed but nothing else is)
|
| A lot of Rust's language people did a lot in Scala. The
| language's are pretty different IMHO.
| nobleach wrote:
| As was explained to me, Rust has heritage from OCaml. If
| one squints, they can even see it still beneath the
| surface. I hear the original compiler was even written in
| OCaml.
| steveklabnik wrote:
| Yes, especially amongst the earliest folks, there was a
| lot of OCaml, and the original compiler was, yes.
| sireat wrote:
| Seeing Scala for the first time seemed this is what happens
| when Java marries Python.
|
| Rust seems like when C++ marries Scala.
|
| Disclaimer: I like C, Python and Scala but not a big fan of C++
| and Java
| vips7L wrote:
| Probably the reason why I don't like rust. Scala is hell for
| me. I've been burned by it so many times.
| blargmaster42_8 wrote:
| Can't take anyone that uses
|
| if(..){
|
| Notation seriously.
| moron4hire wrote:
| Very nice. As a very experienced programmer who has now learned
| more languages than I can remember, I generally look for these
| kinds of cheatsheets whenever I'm learning a new language,
| followed by the official documentation. Other than that, I don't
| personally find tutorials very useful.
|
| The cheatsheets give me a quick intro to syntax conventions, and
| then the official documentation provides all the detail on
| specifics. I'm looking to mentally map how different PL
| constructs common across different languages are expressed in the
| new language I'm learning.
|
| Along the way, I end up learning one or two new PL concepts.
| Fewer these days than in the beginning, hence it gets easier and
| easier to learn new languages.
| kliments wrote:
| Thank you for this comprehensive article! Definitely reading and
| saving it for future reference.
| malwrar wrote:
| This is precisely what I was looking for when I searched for
| "Rust for C++ programmers" in the past. I love the Rust book, but
| I've always thought the common focus on accessibility for newbie
| programmers made it feel tedious for those who are more seasoned.
| I'd love to see more writing like this, maybe even for other
| things like libraries!
| ufmace wrote:
| I've found it's generally really tough to find guides for
| getting into new languages that are written for experienced
| programmers who don't know that language yet. Everything seems
| to be written for complete newbies, or be a dense reference
| that assumes you know almost everything already.
|
| It's a bit annoying, but not much to do except slog through the
| guides and try to write a few programs.
| bluejekyll wrote:
| I found the Rust book to be anything but tedious, as a seasoned
| programmer. As I read it, it made me want to cry thinking back
| on past bugs and issues that I had dealt with that the language
| had been designed to prevent.
|
| It made me think of the days and weeks of debugging that I
| wouldn't have needed to do, had Rust existed.
| pascalgn wrote:
| If you already know C++, https://overexact.com/rust-for-
| professionals/ might be for you (disclaimer: I wrote this)
| morrbo wrote:
| I prefer your guide if it is any consolation. Thanks for
| writing it
| vghaisas wrote:
| In college, I wrote something sort of like this to help students
| prepping for interviews in C++: https://vghaisas.com/code-
| quickref/cpp.html
|
| I quite like the format (though this post is much better than
| mine) of lots of small snippets of code showing how something is
| used.
| hawski wrote:
| It's a great resource. I like such easy list approach, because
| many times new language just needs a translation from concepts
| you already know.
|
| I have a problem understanding how temporaries work in Rust. At
| least from what I see there is a difference between a temporary
| inside a vec that I bind somewhere to then pass it somewhere and
| a temporary inside vec constructed inside method invocation. I
| asked on SO [0], but did not receive satisfactory answer, or I'm
| too dense to understand it.
|
| [0] https://stackoverflow.com/questions/64705654/why-i-get-
| tempo...
| k1t wrote:
| Incredible. Great job.
|
| Oh, I guess it's a year old - but still, extremely good.
| emerged wrote:
| This seems good but it starts using borrow in a bunch of examples
| without saying what it even is.
| dimmuborgir wrote:
| Previous discussion:
| https://news.ycombinator.com/item?id=22448933
| minimaxir wrote:
| I suppose we can now put (2020) in submission titles. :P
| gpvos wrote:
| A grace period of about one to two months seems reasonable.
| kaleidawave wrote:
| Was initially sceptical to this but after skimming think this is
| actually a very good introduction. I do like the brevity of it
| compared to the walls of text in the official rust one. Although
| this does give an illusion that Rust is very simple/easy to learn
| but any beginner will find that anything more than "Hello World"
| or "2 + 4" is 10x more difficult than writing in a interpreted
| language. Not because Rust syntax is difficult but the
| constraints it introduce require more thought of the design of
| the program.
|
| The article also skims over the single ownership model which is a
| big difference with Rust. And it does miss about creating macros,
| cells, threading & mutexes, heap allocated types, unsafe code,
| Rc, std::mem, and the whole crates and cargo ecosystem. Which is
| why I think this should have been titled "half-hour introduction
| to Rust syntax". Hopefully this does bring more people on the
| Rust train. I think 2021 will be a good year for Rust :)
| fasterthanlime wrote:
| Since a lot of folks take issue with the article's title, think
| of it as "If you had only a half hour to learn Rust, here's
| what I'd tell you".
|
| If you have more, do engage in a joust^W friendly collaboration
| with the compiler, which will get you quite far since
| diagnostics are a first-class feature :)
| jokethrowaway wrote:
| This is great!
|
| You probably want to add feeling_lucky: bool as an argument to
| fair_dice_roll()
| laydn wrote:
| What I would like to also see in these types of well written
| articles is the answer to questions like "what can you do with
| Rust that you can not do with C?"
| fasterthanlime wrote:
| This may answer part of your question -- it's focused on
| strings but draws parallels with C all along:
| https://fasterthanli.me/articles/working-with-strings-in-rus...
| pjmlp wrote:
| Having to ask for permission to corrupt memory.
| psanford wrote:
| Write code that is memory safe.
| cesarb wrote:
| Most answers will focus on safety, but setting that aside,
| there's one thing Rust has which AFAIK C doesn't have: fat
| pointers. They're the implementation detail behind both array
| slices (keeping together the pointer to the first element and
| the length) and trait references (keeping together the pointer
| to the object and the pointer to the vtable).
| sanmak wrote:
| Snippets looks quite impressive. But if it's segregated into
| different post like https://flaviocopes.com/ did, then it'll be
| much helpful.
| mrlonglong wrote:
| It only took me a couple of hours to port one of my old C
| programs, an utility to produce a hexadecimal and ASCII dump to
| Rust. The Borrow checker didn't even faze me. All I needed was
| plenty of Google-fu and my coding skills. JetBrains CLion and git
| are also very useful tools.
| rualca wrote:
| > It only took me a couple of hours to port one of my old C
| programs, an utility to produce a hexadecimal and ASCII dump to
| Rust.
|
| Writing C code with Rust is a very different experience than
| converting C code to idiomatic Rust. There is more to porting
| than doing 1:1 conversions between keywords.
|
| And by your description your utility basically reads words and
| prints their value. That doesn't really venture too much beyond
| the hello world territory.
| mrlonglong wrote:
| u8s, actually. But yes, you are right that was a very simple
| port. I to plan to do a port that's more complicated soon.
| chamakits wrote:
| I had a similar experience porting a relatively straightforward
| and simple CLI utility I had written in C.
|
| Having said that, when I've faced real challenges with Rust
| (and the borrow checker) it's been with bigger longer running
| applications, like a webapp, or a long running service.
|
| I have no doubt part of that comes I have a stronger background
| in garbage collected languages, so my mindset when developing
| larger applications is in that mode. I'm sure with enough
| practice I'd get it, but there were many things that I just
| couldn't replicate one to one in Rust. Not that they weren't
| possible, but they were just different enough that I couldn't
| figure it out without being more comfortable in understanding
| the language, and I just haven't dedicated the time needed to
| it.
|
| Will likely go back to it at some point, as it is an
| interesting approach to programming, with lots of upsides.
| mrlonglong wrote:
| My biggest issue was trying to print the contents of u8 as a
| character. In the end this was actually as simple as writing
| print!("{}", line[i] as char), no print specifiers needed.
|
| I may do another more complicated port soon. I love CLion.
| mikewarot wrote:
| The first I'm hearing of the "borrow checker"... so I started
| reading this https://blog.logrocket.com/introducing-the-rust-
| borrow-check..., and I got to the part where it says
|
| "Your programs have access to two kinds of memory where it can
| store values: the stack and the heap."
|
| They left out variables, which is odd.
| coldtea wrote:
| How are variables not in either the stack or the heap?
| mikewarot wrote:
| When you write a program, heap variables are allocated
| using NEW or Malloc... stack variables are local to a
| procedure or function, the rest are in the Var block before
| your code, and are neither on the heap, nor the stack.
| They're global to the program, or the unit.
| coldtea wrote:
| You mean global/static variables?
|
| Yeah, those are not mentioned. It also doesn't mention
| constant storage...
|
| That said it's not like they're the bread and butter of
| programming for their lack of mention to be that "odd" as
| the parent implies.
| Aeolun wrote:
| Wouldn't that mean they're on the heap by default? Your
| program will have to malloc _something_ if they don't go
| on the stack.
|
| (My low level knowledge is limited, may be completely
| wrong)
| coldtea wrote:
| In some (interpreted mostly) languages they are. Like
| some also don't have a stack at all.
|
| But in the most common languages, there is special
| storages for globals, statics, and constants, which is
| what the grandparent means (e.g. the DATA section).
| mcsalgado wrote:
| In the 9th code snippet that's not an example of variable
| shadowing, it's just variable reassignment. Shadowing involves
| variable assignments in different scopes.
|
| https://en.wikipedia.org/wiki/Variable_shadowing
|
| edit: I should've called it "variable redefinition" or something
| like that I guess, my mistake. Reassignment is definitely not the
| correct terminology for this.
|
| Still, it's not shadowing because the new binding of 'x' is not
| effectively shadowing some other 'x' name, it's just taking its
| place in the same scope. And this is orthogonal to the memory
| allocation of the assigned objects.
| stormbrew wrote:
| There is effectively an implicit scope created by the let
| binding. In rust you can't reassign a variable without it being
| mut. The two `x`s are separate variables named x and are not at
| any point mutated. Reassignment would look like this:
| let x = 1; x = x + 1; // <- error[E0384]: cannot assign
| twice to immutable variable `x` let mut x = 1;
| x = x + 1; // ok!
|
| This obviously matters very little for an integer, but it is
| relevant to more complex types.
|
| You can actually see the scopes, and the progress of variable
| liveness, if you run the compiler out to the MIR intermediate
| language: fn main() -> () { let
| mut _0: (); // return place in scope 0 at
| src/main.rs:1:11: 1:11 let _1: i32;
| // in scope 0 at src/main.rs:2:9: 2:10 scope 1 {
| debug x => _1; // in scope 1 at
| src/main.rs:2:9: 2:10 let _2: i32;
| // in scope 1 at src/main.rs:3:9: 3:10 scope 2
| { debug x => _2; // in scope
| 2 at src/main.rs:3:9: 3:10 } }
| bb0: { StorageLive(_1); //
| scope 0 at src/main.rs:2:9: 2:10 _1 = const
| 1_i32; // scope 0 at src/main.rs:2:13: 2:14
| StorageLive(_2); // scope 1 at src/main.rs:3:9:
| 3:10 _2 = const 2_i32; // scope
| 1 at src/main.rs:3:13: 3:18 _0 = const ();
| // scope 0 at src/main.rs:1:11: 4:2
| StorageDead(_2); // scope 1 at src/main.rs:4:1:
| 4:2 StorageDead(_1); // scope 0
| at src/main.rs:4:1: 4:2 return;
| // scope 0 at src/main.rs:4:2: 4:2 } }
|
| https://play.rust-lang.org/?version=stable&mode=debug&editio...
| mcsalgado wrote:
| Oh interesting, I see now! Thanks for clearing this up.
| bysin wrote:
| In the wikipedia entry you provided, there's an example in
| Rust, similar to the 9th code snippet, that claims it is
| variable shadowing:
|
| https://en.wikipedia.org/wiki/Variable_shadowing#Rust
| red2awn wrote:
| There is literally a Rust example in your wiki link saying that
| this is shadowing. You can even redefine the variable to have a
| different type, how can this be reassignment.
| kd5bjo wrote:
| No, it really is shadowing. The second `let` allocates a new
| memory location in the activation record; all future mentions
| of the variable name will refer to the new location. The old
| location still exists, and may have references to it already;
| references that will continue pointing at the old allocation
| and will not see anything that happens to the new one. If the
| old value has a `Drop` implementation, it will run after the
| second allocation's `drop()`. The two `let` bindings can even
| have completely different types.
| powersnail wrote:
| Isn't variable reassignment a special case of variable
| shadowing, where the new scope closes at the same place as the
| parent scope?
| psyklic wrote:
| In Rust, shadowing is when you "declare a new variable with the
| same name as a previous variable" [1] -- even in the same
| scope. It seems it "fell out" of how the original compiler was
| implemented, and there was more support to retain it than not.
| See: https://internals.rust-lang.org/t/history-of-shadowing-in-
| ru...
|
| [1] The "Rust book" has a good explanation of shadowing, which
| contains a nearly identical example. See: https://doc.rust-
| lang.org/book/ch03-01-variables-and-mutabil...
| aero-glide2 wrote:
| I had no intention of learning Rust, but this title just made me
| do that.
| pddpro wrote:
| Thank you so much for this. I wonder if similar guides exist for
| languages like Go and Julia.
| freedomben wrote:
| Absolutely love the humor in this fn
| fair_dice_roll() -> i32 { 4 }
|
| :-D
| cesarb wrote:
| It's a xkcd reference. https://xkcd.com/221/ (xkcd: Random
| Number)
| wintorez wrote:
| Another great resource: https://learnxinyminutes.com/
| bamboleo wrote:
| I'm surprised AngularJS is on there but React isn't.
| golergka wrote:
| They are open for PRs!
| [deleted]
| Aeolun wrote:
| When I read these articles everything always seems so
| understandable, but I can pretty much guarantee that I won't
| remember much tomorrow.
| axihack wrote:
| Same with me, to learn anything I need to write it down,
| possibly several times.
| stonecharioteer wrote:
| I recommend typing out the entire article as in into an
| editor. After you work your way through it, try the rustling
| course, Rust by Example, the CLI tutorial and then read The
| Book.
| pddpro wrote:
| Have you tried Anki or similar Spaced Repetition System?
| majewsky wrote:
| SRS is really good for learning small, compartmentalized
| knowledge items. Its usefulness degrades quickly when you
| move from knowledge to concepts. I'm currently learning
| Japanese and using several SRS tools to do so. The ones
| that work the best are for characters and vocabulary. I
| also use one for grammar, which is okay-ish but doesn't
| translate as well to the SRS format.
|
| So in the context of programming languages, SRS might work
| if you need to memorize method names or method signatures
| (though I don't see why that is needed in the age of
| autocompletion and instant lookups from inside the text
| editor), but not so much for fundamental language concepts
| (like "how do lifetimes interact with the borrow checker").
| nitred wrote:
| As a Python programmer with limited experience with compiled
| languages, Rust code was more intimidating to read or look at
| than C++, Java or Go. After only an hour, I am overwhelmed by the
| sheer beauty and mature design of this language - it almost reads
| like Python or as well as any compiled language can. I cannot
| believe that I am smitten by Rust within an hour. Its features
| seem, obvious. My experience with Go was frustrating since I felt
| like I had to give up elegance for practicality. I did not expect
| to learn 1-2% of Rust when I woke up today. My thanks to the
| author.
|
| I'm curious what other what other developers who primarily use
| Python think of this article and Rust in general?
| christiansakai wrote:
| Rust makes hard things easy and easy things hard.
|
| Also reading Python code is easier (less syntax noise) on the
| eyes. The article above is very beginner Rust, and I won't rely
| on that to look at actual Rust code in the wild.
|
| If you want to take a look at what actual Rust code in the
| wild, take for example, a web server Actix, and try to figure
| out what the documentation says.
| felipellrocha wrote:
| > Rust makes hard things easy and easy things hard.
|
| I don't agree with this, and, if anything, this reads very
| biased.
|
| Insofar, Rust has made my life a lot easier, and I have not
| run into any major issues aside the borrow checker. And this
| was early on. Two years now playing with the language and I
| barely run into it anymore.
| christiansakai wrote:
| Async has ecosystem fracture issues. Creating graph data
| structures require you to understand more about borrow
| checker.
|
| Majority of people will probably want to use Rust for web?
| Which makes async needs to be ergonomic enough if it wants
| consider wide adoption.
| dralley wrote:
| So does Python. Asyncio is mediocre at best and difficult
| to express certain patterns in. Other libraries are far
| better, but not in the standard library.
| simias wrote:
| I find that advanced Python is quite hard to read. Well, I
| find that advanced dynamically typed languages tend to be
| hard to read in general, because you can never be sure what
| type your inputs and outputs are and what values they can
| take. Usually my
|
| At least idiomatic Python shuns wildcard imports that
| obfuscate where symbols are coming from (that drove me insane
| in Ruby).
|
| On the other hand Rust code tends to be very strict about
| what your types are (even more so than a language like C++
| where metaprogramming is duck-typed by default). It can lead
| to complicated code, but baring some weird operator
| overloading decision you should know exactly what calls what
| from whom when you look at any method or function.
|
| Rust code can be tricky to write at times, but I generally
| find it a pleasure to read. Sure, ultra-complicated generic
| code can be overwhelming, but this complexity would be here
| in one form or the other regardless of the language, Rust
| just forces you to be explicit about it.
| cute_boi wrote:
| "Rust makes hard things easy and easy things hard."
|
| Disagree here. Like article Rust 2018 is very nice and
| ergonomic. Iterators, Lifetime Elision etc are nice to work.
|
| Regarding noise many people consider those noise but I find
| noises like return types etc very useful. Because I can be
| sure the return type. Regarding actual code actix doesn't
| look that bad from examples also.
|
| I use warp and its pleasant to work. The only thing I hate is
| compilation time other than that I don't think I have any
| major criticism against rust. But compilation time is near to
| cpp etc so ...
| christiansakai wrote:
| Actual code examples from Actix isn't that bad but take a
| look at the docs.
| mikepurvis wrote:
| I'm a recent Rust fan (via AoC), but for "easy things
| hard", I would offer input/string processing as an
| example-- regexes, string operations, grammar, etc. I
| _know_ that Rust is forcing me to be correct and handle (or
| explicitly acknowledge that I 'm not handling) my error
| cases, but from the point of view of just wanting to get
| the happy path working, it's a lot more noise to deal with
| compared with what it would look like in Python, eg:
| let re = Regex::new("(?P<min>[0-9]+)-(?P<max>[0-9]+)
| (?P<letter>[a-z]): (?P<password>[a-z]*)").unwrap();
| re.captures_iter(&contents).map(|caps|
| Input { password:
| caps.name("password").unwrap().as_str().to_string(),
| letter: caps.name("letter").unwrap().as_str().chars().next(
| ).unwrap(), min:
| caps.name("min").unwrap().as_str().parse().unwrap(),
| max: caps.name("max").unwrap().as_str().parse().unwrap()
| } ).collect()
| projct wrote:
| If you get rid of unwrap and use `if let` and `match`,
| this code will clean up nicely.
|
| If the code is supposed to be maintainable, you could
| also make something like a FromRegex trait for Input. It
| would be a good idea to try exercism's mentoring thing to
| get better at writing it the easier way the first time.
| The mentoring thing really is what helped me to think in
| ways that made this mess easier to avoid.
| artursapek wrote:
| > I cannot believe that I am smitten by Rust within an hour
|
| This has been my, and a lot of my colleagues', experience with
| Rust. Never have I seen people fall in love with a programming
| language so strongly. And the love lasts for a long time.
| christiansakai wrote:
| Try to use that in real world and see if your love still
| stays put. An hour is not enough to validate Rust.
| artursapek wrote:
| Typical condescending HN response. We are using Rust, we've
| used it to build and ship a successful native desktop app.
| [deleted]
| CRConrad wrote:
| Do you know any Object Pascal programmers?
| ithrow wrote:
| _am overwhelmed by the sheer beauty and mature design of this
| language - it almost reads like Python or as well as any
| compiled language can._
|
| All those lifetime annotations are not sheer beauty or pretty,
| sure they are necessary but not nice to look at if you are
| comparing it to a higher level language.
| nitred wrote:
| I agree it's not pretty. It took me several passes to just
| understand what was going on there. But ownership is
| something I've never come across before and it doesn't exist
| in Python (not to an average user anyway), so it seems a
| little unfair to compare Rust and Python based on that
| feature.
|
| However when you take a high level feature like overriding
| operators which can be done elegantly in Python, for a
| complied language, Rust's way is quite concise, readable and
| to my eyes quite pretty.
|
| Edit: Typos
| globuous wrote:
| Except from that though, it really looks like ocaml, which
| really makes me want to look into rust a little bit more :)
| fasterthanlime wrote:
| Yup, strong similarities there, since the original Rust
| compiler was implemented in OCaml :)
| julenx wrote:
| For those who are curious, here's the source code of the
| original compiler written in OCaml (rustboot)
| https://github.com/rust-
| lang/rust/tree/ef75860a0a72f79f97216...
| the_duke wrote:
| You can write Rust code with almost no lifetine annotations.
| That's heavily dependent on the domain, of course. But for
| relatively simple function signatures they are usually
| inferred correctly, and you can often just clone instead of
| requiring references.
| throwaway894345 wrote:
| Pretty sure if you're deserializing a structure with
| borrowed references you need lifetime annotations. Copying
| things around to pacify the compiler hardly seems elegant.
| the_duke wrote:
| Sure, but that's a performance vs ease of use decision.
|
| Often you don't need to care about the extra allocations
| and can just deserialize to owned types.
|
| The code for owned deserialization certainly ends up
| looking more elegant.
| throwaway894345 wrote:
| It's not just performance, but you now have to go back
| and update every instance of that struct to reflect the
| change in ownership of that member if you can even change
| the member in the first place (e.g., you can't change the
| type of a member of the struct itself is defined in a
| third-party package). Moreover, some instances of your
| struct might be in a tight loop and others might not, but
| now you're committing to poorer performance in all cases.
| Maybe you can box it (although IIRC I've run into other
| issues when I tried this) but in any case this isn't the
| "elegance" I was promised. Which is fine, because Rust is
| a living, rapidly-improving language, but let's not
| pretend that there is an elegant solution today.
| nobleach wrote:
| Yes, you can clone all day long and just reuse variable
| names as if you were writing JavaScript, but what does that
| do to your memory allocation?
| throwaway894345 wrote:
| To be clear, JS doesn't require cloning because it has a
| gc. Not sure what you're getting at with reusing
| variables names...
| nobleach wrote:
| What I mean is, if one does: const obj1 =
| { a: 32, b: 42 }; function foo(ref) { ref.a = 0; }
| foo(obj1); console.log(obj1);
|
| in JavaScript, one is just using the variable name as a
| "holder" of some value. One doesn't have to designate
| that that variable is being passed by reference. If one
| wanted to actually copy that object, they'd have to
| devise a mechanism to do so. In Rust, if someone doesn't
| specify, using the & symbol, that something is a
| reference, it'll end up moving the value.
|
| Basically all I was saying is one can not approach
| writing Rust with a Java/JavaScript mindset. (That a
| variable is just a bucket holding a value). Care needs to
| be taken when referencing a variable as it may need to be
| moved, copied/cloned or referenced. In the case of
| copying, another memory allocation is done. So if someone
| approaches Rust from the standpoint of "this word
| represents a value, and I'm going to use it all over the
| place", they can find themselves blindly allocating
| memory.
| throwaway894345 wrote:
| Oh, by "reuse variable names", you simply mean that
| values aren't moved, i.e., that JS lacks move semantics
| or an affine type system. That's a bit different to
| "reusing variable names", which you can do in Rust as
| well provided the variable holds a (certain kind of?)
| reference.
| gpm wrote:
| _Most_ languages just clone all day long, it 's not that
| bad, rust clones (like most languages) are just to the
| first reference counted pointer after all.
| the_duke wrote:
| Well, yes and no.
|
| Eg cloning a string leads to an extra allocation and a
| memcopy.
|
| If you want to get a similar performance profile to GC
| languages, you have to stick your types behind a
| `Rc<T>>/Arc<T>` or `Rc<RefCell<T>> / Arc<Mutex<T>>` if
| you need mutability.
|
| But modern allocators hold up pretty well to a GC, which
| amortizes the allocations. The extra memcopying can be
| less detrimental than one might think.
| throwaway894345 wrote:
| "Yes and no" is too generous; most languages clone only
| very infrequently (basically only for primitives where
| there is no distinction between a deep and shallow copy).
| For complex types (objects and maps and lists) they pass
| references (sometimes "fat" references, but nevertheless,
| not a clone).
| volta87 wrote:
| I think that being able to write down the lifetimes in the
| language is beautiful.
|
| You don't have to do it, but if you want to do it, being able
| to do so in a way that's verified and enforced by the
| toolchain beats doing so in a documentation comment.
|
| Now every time I read a doc string saying that I need to
| "deepcopy" something in Python for some API usage pattern to
| work properly I cringe.
| fasterthanlime wrote:
| That's one of the things that get me about Rust discourse:
| it seems that "Rust is pain in exchange for performance" is
| a common misconception. Rust is discipline in exchange for
| performance _and correctness_. A GC lets you be relatively
| worry-free as far as memory leaks go (and even then..) but
| it doesn 't prevent a lot of the correctness problems the
| borrow checker would.
|
| With a checker you're forced to think: do I really want to
| pass a copy/clone of this? Or do I want to let that
| function borrow it? Or borrow it mutably?
| harikb wrote:
| While I get the point about data-races, a "GC" doesn't
| make/help you leak memory - you have simply postponed the
| free to a later point in time.
|
| Assume you had some code that takes a file name and calls
| open on it. One day you decide you want to print that
| filename before you open it. Naive code will cause the
| name to "move" to print and unusable to the open in next
| line. Even though it is perfectly understood by all
| parties that there is no threading involved and print
| would finish before the next use of that string. Yes, I
| can create a borrow or clone, but having to think of it
| every single line of code even when there is only one
| thread of execution is really painful
|
| Edit: I get print is a macro, but imagine a detailed
| logger for this case.
| fasterthanlime wrote:
| I'd argue the exact opposite. Languages that _don 't_
| have a concept of ownership, and a borrow checker, and
| don't explicitly say if they want ownership, a reference,
| or a mutable reference, force you to keep all of these
| details in your head.
|
| Here, if I have a `&T` and I try to call a function that
| has a `&mut T`, the compiler will tell me that's not
| gonna work - and then I can pick whether I want _my_
| function to take a ` &mut T`, or if I want to make a
| clone and modify _that_ , etc.
|
| There's a learning curve, it's a set of habits to adopt,
| but once you embrace it it's really hard to go back to
| languages that don't have it! (See the rest of the
| comments for testimonials)
| millstone wrote:
| I think both points are right. There's times when it's
| useful and desirable to be specific about lifetimes, and
| there's also times where it's annoying noise.
|
| Bignum arithmetic is an example of the latter. You want
| to just work with numbers, and in Python you can, but in
| Rust you must clutter your code with lifetimes and
| borrows and clones.
|
| Swift's plan to allow gradual, opt-in lifetime
| annotations seems really interesting, if it works.
| CDSlice wrote:
| Bignum arithmetic actually is pretty simple in Rust if
| you use the right library. Rug[0] makes using bignums
| look almost just like using native numbers through
| operator overloading.
|
| [0] https://crates.io/crates/rug
| millstone wrote:
| The operator overloading is nice but you still get
| smacked in the face right away by the borrow checker.
| Simple stuff like this won't compile ("use of moved
| value"): let a = Integer::from(10);
| let b = a + a;
| rapsey wrote:
| All those? Very small amounts of an average Rust code base
| will have lifetimes.
| felipellrocha wrote:
| You get used to it, and you don't really need to use it most
| of the time. Only for more complicated things, but by that
| point, it's second nature.
| thisisusername wrote:
| As another Python programmer I also agree. Rust's features are
| very mature especially compared to an old dinosaur like C. I
| only wish its syntax was more like Swift's which is more
| pleasing to the eyes and was also made by the same guy.
| dagmx wrote:
| Minor note,. Graydon created rust and worked on Swift. He
| didn't create Swift however.
|
| That said...both languages read like close siblings to me to
| the point I find it annoying switching between the two
| because I keep trying to use each ones language semantics in
| the other subconsciously.
| thisisusername wrote:
| I feel like I'm being bullied and nitpicked but you're
| speaking politely so I'm confused.
| [deleted]
| thisisusername wrote:
| Stop narcissistically using peer pressure to turn people
| against me. It's really gross and creepy and I will not
| tolerate it.
|
| Why am I flagged for standing up for myself like a good
| person should?
| bccdee wrote:
| I was mostly a Python user, and now I primarily write Rust when
| I can. It's an absolutely gorgeous language, especially for
| being so practical.
|
| There's a bit of a progression with Rust, where at first you
| see the examples and you go "this language is so beautiful!"
| Then you try to write something nontrivial in Rust and you go
| "wow the compiler will NOT stop yelling at me, how does anyone
| write anything in this language?" Rust has a fairly austere
| learning curve in general, and it takes some getting used to.
|
| That passes, though, and then you really do get to experience
| the elegance and power which sold you on Rust in the first
| place. There's a period where writing Rust feels substantially
| slower that writing in anything else, but that passes too.
|
| It really is as good as it sounds, but it might take a while
| before you're accustomed enough to Rust's paradigm that it
| feels that way.
| mikeschmatz wrote:
| Rust is a complete pain for the types of problems Python is
| used for. Same for Go/Java.
| dmit wrote:
| I used to use Ruby for small (100-500 loc) scripts to parse
| various CSV/JSON documents. You craft a couple perfect
| stanzas of immaculate code to do what you need and you feel
| great. Then you run it and turns out you forgot an `end`
| somewhere. Fuck. You run it again, and the name of the hash
| map variable is unknown, because you changed it at the last
| moment to make it more descriptive. Fuck. There, fixed
| everything. Run it again. Running for a couple seconds now
| with no errors -- pop the champagne! Wait, what's that? Row
| #998 of 1000 had an unexpected type of value? Fuck. Fix it,
| ship it. Wheel, snipe, and celly.
|
| At some point I just started writing these things in Rust
| instead. Describe what I want deserialized as a struct. List
| the fields I want as enum variants. What's that, rustc, the
| "name" field is optional? Ok, that makes sense, I'll handle
| this right away. Done. Hey, rustc, how come people talk about
| fighting you all the time when you're actually the world's
| greatest pair programmer?
| zem wrote:
| D is also worth a look as a compiled C- family language that
| can read like python. https://bitbashing.io/2015/01/26/d-is-
| like-native-python.htm...
| bitL wrote:
| Look into C++17, that one makes C++ look like Python but with
| worse basic libraries (not that Python ones are great either).
| rapsey wrote:
| Unfortunately one can't live solely in C++17. The sheer
| amount of syntax and knowledge required to write C++
| productively is insane.
| eeZah7Ux wrote:
| > I am overwhelmed by the sheer beauty and mature design of
| this language - it almost reads like Python
|
| Sarcasm?
| nitred wrote:
| _"... or as well as any compiled language can. "_
|
| Some syntax is close to Python so some mental load is
| minimized, i.e use of _snake_case_ , _self_ , _None_ and type
| annotation syntax, dict unpacking.
|
| Some lines read like sentences i.e. for loops, single line if
| statements, _impl Foo for Bar_ etc. Some design choices also
| read better I think, for example, _let_ reads better than
| _var_.
|
| Of course such preferences are personal. I've read other
| comments that mention that the tutorial covers only basic
| Rust features and it can get much more complicated when using
| more advanced features.
|
| Edit: Added sentence about advanced features.
| faitswulff wrote:
| This podcast might be relevant: the creator of Flask who is now
| using Rust: https://realpython.com/podcasts/rpp/18/
|
| Edit - actually I was probably thinking of this podcast with
| the same interviewee: https://rustacean-
| station.org/episode/004-rust-in-production...
| nitred wrote:
| Just started listenting to it. It's exactly what I was
| looking for, thank you. Armin Ronacher's opinion on such
| things would hold a lot weight in my head.
| jgraham wrote:
| I've shipped relatively lots of code in Python and a little bit
| in Rust.
|
| For any project where performance or correctness are
| significant concerns I'd much rather use Rust than Python. It
| provides a lot more tools to help you write correct code, and
| express invariants in a machine-checkable way. This means that
| they are maintained when the code changes, even when multiple
| contributors are involved. I'm must more confident in my
| ability to ship correct code in Rust and maintain that
| correctness over time.
|
| Rust also doesn't have the performance ceiling (floor?) of
| Python, either for single threaded programs, or -- especially
| -- for those that benefit from concurrency or parallelism. Of
| course for some progames there's a clear hot loop that you
| could implement as a native extension in Python, but other
| workloads have relatively flat profiles where the performance
| bottlenecks are making allocations or similar.
|
| As well as the actual language features, the commitment to
| backward compatibility from the Rust authors means that you
| don't get regular breakage simply from updating to a newer
| version of the language. I think Python 2 being 2.7 for such a
| long time gave people a false impression of how stable a
| foundation Python provides and the fact that point releases of
| 3.x often cause problems feels like it causes a lot of
| unnecessary makework for Pyton users and is rather offputting.
|
| That doesn't mean I'd always choose Rust of course. You do
| require more upfront design to get something that works at all.
| Some projects also benefit greatly from not requiring a compile
| step and making use of the ubiquity of a Python interpreter.
| And I think I'd find it difficult to justify using Rust for a
| typical web backend that's mostly composing together various
| well-tested libraries to provide an API on top of a database.
| unethical_ban wrote:
| My only bone to pick with this commentary is that it is 2020
| and people are still complaining about Python as being
| unstable because of 2 -> 3.
|
| It was a rough transition, to be sure. Python2 was released
| 20 years ago, and Python3 12 years ago. It is a pretty stable
| language.
| duckerude wrote:
| It's specifically complaining about point releases of 3.x,
| it only mentions 2 in an unrelated way.
|
| The fix for https://bugs.python.org/issue40870 caused me
| some grief when upgrading from 3.8.3 to 3.8.4 (though to be
| fair, the ast module has different stability guarantees).
| johnmaguire2013 wrote:
| I don't think the parent is talking about Python 2 -> 3. I
| think they are pointing out that for many developers,
| moving to Python 3 happened very late. That means they ran
| 2.7 since 2010 (roughly 10 years now.) Now that they are on
| 3.x, they get issues with each new 3.x release.
|
| The argument is that being on 2.7 for so long gave a false
| impression of the language being more stable than it is -
| developers just weren't using new versions.
| gpm wrote:
| My housemate was just rolling back from python 3.8 to 3.7
| yesterday due to a backwards incompatible change breaking a
| library... it's not just 2 -> 3 that makes python
| relatively unstable compared to rust.
| alexanderdmitri wrote:
| What the issue?
| wokwokwok wrote:
| > There is a special lifetime, named 'static, which is valid for
| the entire program's lifetime.
|
| I've heard this many times before, but as the guide[1] says:
|
| "You might encounter it in two situations... Both are related but
| subtly different and this is a common source for confusion when
| learning Rust."
|
| 'static means _different things_ for references and trait
| objects.
|
| ie.
|
| 'a: 'static --> reference with lifetime 'a lives forever and can
| never be dropped.
|
| T: 'static --> Type T has no references in it; it is effectively
| 'entirely owned' by the owner of an instance of T.
|
| These are totally different things with the same name.
|
| (I believe technically there are actually three; `<T: 'static >`
| is a type constraint and `T + 'static` is a trait bound, but that
| both mean the same thing as far as I know)
|
| [1] - https://doc.rust-lang.org/rust-by-
| example/scope/lifetime/sta...
| pornel wrote:
| The missing information here is that lifetimes _don 't apply at
| all_ to types that don't contain any borrowed references (such
| as `i32`, or self-contained `String`).
|
| So `T: 'static` doesn't require types to live for the entire
| duration of the program. It requires borrows _if there are any_
| to be valid for that long. If there are no borrows involved,
| then 'static is ignored.
|
| In practice `T: 'static` should be understood as "all temporary
| references are forbidden here".
| m-ou-se wrote:
| `T: 'a` means that you _may_ keep values of type T around for
| lifetime 'a, but not that they _will_. So `T: 'static` means
| that you may keep values of that type around forever, as they
| do not refer to anything that doesn't live forever.
|
| So neither `&'a i32` nor `MutexGuard<'a, i32>` are 'static
| (unless 'a is), because you shouldn't keep references like that
| around longer than the stuff it points to. But i32 by itself
| satisfies i32: 'static, because it's perfectly fine to keep an
| i32 around forever. (But that doesn't mean that every i32 will
| stick around forever.)
| GolDDranks wrote:
| The wording that "'static means different things" is a bit
| misleading. It means the same thing, but the meaning different
| because of the context:
|
| Lifetime: lifetime means that the first lifetime outlives (is
| as long or longer) the second
|
| Type: lifetime means that the type is constrained by the
| lifetime. Because 'static means "the lifetime of the whole
| process". That means that the type is not constrained.
| wokwokwok wrote:
| I find it very confusing.
|
| T: 'a is T outlives 'a; but types are not generated at
| runtime.
|
| All types are static; which is to say they are created at
| compile time and exist for the lifetime of the program.
|
| Or does rust generate type variants on the fly at runtime?
|
| I didn't think it did...
|
| It is a _constraint_ applied to arguments at _compile
| time_... but r, that's what I thought anyway.
| dbaupp wrote:
| A type constraint like T: 'a or T: Trait is constraining
| values of type T, not the type T itself. That is T: 'a is
| saying "all references in values of type T live at least as
| long as 'a". This includes 'a = 'static and the vacuous
| case of T containing no references.
| DougBTX wrote:
| > T: 'a is T outlives 'a; but types are not generated at
| runtime.
|
| Yes, that's true, but you can make it a bit more specific
| by saying "all the references in T outlive 'a". Then it
| should make more sense, as references are generated at
| runtime.
|
| This gets to the heart of what makes Rust an interesting
| language, as references are generated at runtime, but how
| long those references are valid for is checked at compile
| time using lifetime bounds.
| kaoD wrote:
| Types are not generated at runtime, lifetimes _are_ types
| (although they cannot be constructed).
|
| T<'a> and T<'b> are different types altogether (although,
| being generic, they can resolve to the same type if 'a ==
| 'b, but it's not required). All this happens at compile
| time.
|
| When you say T: 'a you say that T is a subtype of 'a hence
| it lives longer.
|
| https://doc.rust-lang.org/nomicon/subtyping.html
|
| Maybe you're being confused by misconception 1 here?
|
| https://github.com/pretzelhammer/rust-
| blog/blob/master/posts...
|
| Type T, being generic, can be an OwnedStruct, but also an
| &'a BorrowedStruct or a StructWithReferences<'a>. The owned
| one is a subtype of 'static since it's owned, but the ones
| with lifetimes are subtypes of 'a which itself (being a
| generic lifetime) can be a subtype of 'static or any other
| lifetime. Again, all this happens and is checked at compile
| time. This ensures that at runtime, the actual references
| are alive as per their lifetimes without explicitly
| checking them anymore.
| wokwokwok wrote:
| You misunderstand; what confuses me is how 'static can
| mean the _same thing_ in both of these contexts.
|
| T: 'static does _not mean_ the references in T must exist
| for the lifetime of the application.
|
| Ie. the lifetime constraint on T isn't the same 'static
| from &'static where the reference must life for the
| entire lifetime of the application.
|
| Types are static. T: 'static applies to instances at
| runtime.
|
| These instances do not have and are not related to the
| 'static lifetime which is "the entire length of the
| application".
|
| I accept:
|
| > Type: lifetime means that the type is constrained by
| the lifetime.
|
| I don't accept the explanation:
|
| > Because 'static means "the lifetime of the whole
| process". That means that the type is not constrained.
|
| A does not follow from B.
|
| If you want something to mean "A type cannot have
| references in it" then invent a 'noref lifetime.
|
| 'static in this context would mean that all members of T
| must be 'static, which means that _all instances of T
| must be 'static_.
|
| It does not mean that.
|
| I don't understand why they have the same name; they are
| not the same thing; it is an example of failure to have
| orthogonality in the language design in my opinion.
| AsyncAwait wrote:
| > T: 'static does not mean the references in T must exist
| for the lifetime of the application.
|
| It means that T does not have non static references, so
| it is not a requirement that it lives for the lifetime of
| the application but can do so.
| GolDDranks wrote:
| You seem to misunderstand what type : lifetime means.
|
| > 'static in this context would mean that all members of
| T must be 'static, which means that all instances of T
| must be 'static.
|
| Your "which means that" isn't true. It doesn't mean that.
| The syntax type : lifetime indicates that the values of
| the type MUST BE ABLE to outlive the lifetime. It doesn't
| mean that they NEED to outlive the lifetime.
|
| This means, for example, i32 : 'static even in the case
| doesn't live the whole 'static lifetime. It COULD live,
| though, if the author of the code allocated it
| statically.
| kaoD wrote:
| Sorry, I probably edited my comment while you were
| replying and added a couple links.
|
| Check misconception 2 here, I think it addresses your
| point.
|
| https://github.com/pretzelhammer/rust-
| blog/blob/master/posts...
|
| EDIT to your edit:
|
| > 'static in this context would mean that all instances
| of T must be 'static.
|
| You mean in T: 'static?
|
| No. It means that any instance passed as type T must be
| bound by 'static and therefore could be held up to the
| end of 'static. This does not mean that they're allocated
| at compile time, it just so happens that static variables
| (allocated at compile time) are 'static but the causality
| is reversed.
|
| > If you want something to mean "A type cannot have
| references in it" then invent a 'noref lifetime.
|
| It _can_ have references in it! As long as they 're bound
| by 'static.
|
| Here's an example: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
| [deleted]
| wokwokwok wrote:
| Oh, I've read that.
|
| I just maintain that the word 'static is being overloaded
| here to mean multiple different things.
|
| 'static is not the "lifetime of the entire application"
| when it is used in the context of T: 'static.
|
| > It can have references in it! As long as they're bound
| by 'static.
|
| :)
|
| ...but it can also have values in it which are not
| 'static.
|
| So is T: 'static, or not?
|
| It's arbitrary semantics; ...but my take on it is:
|
| - IF you take "x is 'static" as meaning the "X is valid
| for entire lifetime of the application"
|
| then if:
|
| - x: &'static 'is static' and must be valid for the
| entire lifetime of the application.
|
| I would expect:
|
| - x: T + 'static 'is static' and must be valid for the
| entire lifetime of the application.
|
| I'm happy to agree that's not what it _does_ mean, what I
| 'm saying is that it is _inconsistent_ for it not to mean
| that.
| AsyncAwait wrote:
| > ...but it can also have values in it which are not
| 'static.
|
| I don't think that's right. It can only have references
| which live at least as long as 'static does (or longer,
| but 'static is the longest so...)
| kaoD wrote:
| I think he means owned values (notice he didn't say
| "other references") But actually... owned values are
| bound by 'static!
| kaoD wrote:
| > 'static is not the "lifetime of the entire application"
| when it is used in the context of T: 'static.
|
| Yes it is.
|
| T: 'static means T can live _up to_ the end of the
| "lifetime of the entire application".
|
| > ...but it can also have values in it which are not
| 'static.
|
| I don't follow. Values are indeed bound by 'static. If
| they weren't we wouldn't be able to pass values to other
| threads (which can potentially last as long as our
| application's main thread).
|
| > 'static is not the "lifetime of the entire application"
| when it is used in the context of T: 'static.
|
| It is. Any owned instance without non-'static references
| inside can live up to the "lifetime of the entire
| application". You might drop them earlier if you wanted
| to, but you don't _have to_ since it can live up to the
| "lifetime of the entire application" and therefore can be
| passed for example into a thread that can hold the value
| up to the end of the "lifetime of the entire
| application".
|
| Any owned value can be held indefinitely as long as the
| program is running.
|
| I'm taking a guess here: you mean that values' lifetimes
| can be constrained (I guess you mean by dropping the
| actual value). But it's the owner the one that ended it
| earlier, not the caller (where 'static applied). You will
| never be able to have an owned value with a lifetime
| shorter than 'static without dropping it and, if you drop
| it, you cannot pass it anywhere. Hence why any owned type
| that is passed is, by definition, bound by 'static.
|
| > ...but my take on it is:
|
| > - IF you take "x is 'static" as meaning the "X is valid
| for entire lifetime of the application"
|
| > then if:
|
| > - x: &'static 'is static' and must be valid for the
| entire lifetime of the application.
|
| > I would expect:
|
| > - x: T + 'static 'is static' and must be valid for the
| entire lifetime of the application.
|
| Your expectations are correct and that's what it is. Just
| replace "must be valid" with "can live up to".
|
| That's why you need to pass T: 'static to threads,
| because a separate thread needs something to hold up to
| the end of the application since a thread can potentially
| never end.
|
| https://doc.rust-lang.org/std/thread/fn.spawn.html
| wokwokwok wrote:
| Fair I guess; we're just arguing semantics. The point I
| was originally making is that:
|
| 'a: 'static is read "'a outlives 'static" [1]
|
| T: 'static is read "T is bounded by 'static" (apparently,
| although I can't find a reference to it).
|
| The syntax is the same, the meaning is different.
|
| Maybe the 'static part of these two things _is_ the same,
| but they seem to me to:
|
| - mean different things
|
| - use the same syntax
|
| It is what it is I guess... just confusing as to why it
| was decided to use _the same_ syntax for these things,
| instead of something different.
|
| You could argue that adding new syntax makes the language
| more complicated; but I'm not sure. Does it make it less
| complicated when you overload the same syntax with
| multiple different contextual meanings?
|
| Opinions probably vary.
|
| [1] - https://doc.rust-lang.org/reference/trait-
| bounds.html#lifeti...
| [deleted]
| kaoD wrote:
| What confuses me is... why do you think the meaning is
| different? There is no meaning overload. It's a single
| meaning.
|
| T: 'static would happily typecheck with &'a str if 'a:
| 'static.
|
| T: 'static typechecks:
|
| - OwnedValue
|
| - OwnedValueWithReferences<'a> where 'a: 'static
|
| - &'a ReferencedValue where 'a: 'static /// &'static
| ReferencedValue
|
| - Foo<&'a Bar> where 'a: 'static /// Foo<&'static Bar>
|
| ...and more.
|
| See the example here: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
|
| Notice how bar2 has a &'a str where 'a: 'static and it
| can be happily passed to bar.
|
| Of course in T: 'static you're subtyping a type and in
| 'a: 'static you're subtyping a lifetime (which implicitly
| subtypes the type that it's applied on)... but the ":
| 'static" part means exactly the same: "the left part of
| this bound can live up to the end of the application".
| Whether it's a lifetime, a borrowed type or an owned type
| does not matter.
|
| > It is what it is I guess... just confusing as to why it
| was decided to use the same syntax for these things,
| instead of something different.
|
| Because they are the same.
|
| We could of course separate them into 'noref,
| 'yesrefbutstatic, 'staticref, etc. But then we'd have a
| needlessly restrictive std:.thread::spawn that would
| accept only Owned, or only Owned<'static> or only
| &'static Referenced. The implications are the same, hence
| they're the same. We wouldn't gain anything and we'd be
| needlessly restricted.
|
| A simpler way to put it: owned values have an implicit
| 'static lifetime.
| wokwokwok wrote:
| What you say makes sense... but I struggle to reconcile
| it with reality.
|
| If "the left part of this bound can live up to the end of
| the application" then why is &a not 'a where 'a: 'static?
| a can live up to the end of the application. &a can live
| up to the end of the application.
|
| Why is the result "argument requires that `a` is borrowed
| for `'static`" fn foo<'a: 'static>(a:
| &'a str) { println!("{}", a) } pub fn main() {
| let a = "hello world".to_string(); foo(&a);
| }
|
| So I guess I'm going to have to just agree to disagree on
| this one and bow out of this conversation thread I'm
| afraid.
|
| [1] -- https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
| kaoD wrote:
| What?
|
| If you do 'a: 'static, then you just said 'a is at least
| as long as 'static.
|
| When you borrow the String, you just created a lifetime
| that is not as long as 'static. Variables are dropped
| (and hence unborrowed) in reverse order. So 'a will
| necessarily be dropped before its owner, hence it's
| shorter than 'static.
|
| As you can see it complains that it's dropped at the end
| of main() even though it should be borrowed for 'static.
| If this was an owned value it would NOT be dropped at
| main() since it would be moved into the function on call.
|
| Nothing surprising here.
|
| > &a can live up to the end of the application
|
| Nope. Imagine spawning a thread and passing &a but
| keeping 'a' in your main thread.
|
| > bow out of this conversation thread I'm afraid
|
| Welp I did what I could.
| GolDDranks wrote:
| > a can live up to the end of the application. &a can
| live up to the end of the application.
|
| Nope, a reference to a stack frame can't live up to the
| end of the application. The stack frame gets deallocated
| and the referent ceases to exist; therefore the reference
| you're creating in your linked example doesn't outlive
| 'static. `main` is not an exception to this in Rust.
| DougBTX wrote:
| > These are totally different things with the same name.
|
| Another way to think about it is that "T: 'static" restricts
| all references in T to be static, in the same way that "'a:
| 'static" restricts 'a to 'static. The case when T doesn't
| contain any references is then just a boring base case.
| mikewarot wrote:
| I was a complete Nube an hour ago... I understand info from Nubes
| has special value, so I'll be as explicit as I can.
|
| I must be slow, being an old fart... I've been at it for 53
| minutes and got about 1/2 way before all the questions in my
| brain stacked up to "full".
|
| I'd add a recommendation at the top of this to have a Rust
| compiler handy.
|
| {} were called braces when I learned programming, [] were
| brackets... this tripped me up, Unicode calls these {} curly
| brackets ?!? (Why did it trip me up? Because on my screen in non-
| dark mode, { and [ look identical due to my eyesight, and I
| assumed I was looking at [ because the text said that's what it
| was... as you get older, you'll understand)
|
| I don't understand why b=a; c=a; <-- doesn't work because a is
| "used up"???
|
| I'll get a Rust compiler and start again.
|
| I'm allergic to "macros" as they have had a special place in hell
| because of their misuse in C... I hope Rust is more sane.
| aliceryhl wrote:
| Regarding a getting used up, the Rust compiler enforces a
| single-ownership principle where all values must have a single
| owner. If you move ownership of a to b, you cannot use a
| anymore as it no longer has ownership of the value.
|
| The only exception to the above is if a type "is Copy". This
| means that values of this type can be copied very cheaply, and
| in this case the compiler will allow you to use it multiple
| times, which is implemented by it being duplicated on each use.
|
| As for macros, they are nothing like C macros.
| BatmanAoD wrote:
| > I'd add a recommendation at the top of this to have a Rust
| compiler handy.
|
| If you haven't already, check out the Playground:
| https://play.rust-lang.org/
|
| It's reasonably full-featured for a web IDE (much more so than
| the Go playground), and it includes many commonly used
| packages.
|
| > Because on my screen in non-dark mode...
|
| The little sun icon in the lower left corner of the page turns
| on dark mode! Hopefully that helps.
|
| > I don't understand why b=a; c=a; <-- doesn't work because a
| is "used up"???
|
| This is something called "linear typing", and it's admittedly
| pretty unusual in a mainstream language.
|
| The core idea is that the assignment operator _only ever_
| creates a "shallow" (bitwise) copy of data; it never invokes
| anything like C++'s copy assignment operator. For types that
| are "plain old data" (like primitives), the old and the new
| values are fully independent, so the assignment works the same
| way it would in most languages, i.e., `a` is not "used up".
| This is what other commentors mean when they say that
| primitives "implement `Copy`". But if the old value has
| pointers or references, then the two values are not
| independent: after the bitwise copy, they both have pointers to
| the same data. Since data can only ever be shared explicitly in
| Rust, and the assignment operator never performs a deep copy,
| the old value, `a`, is considered invalid and cannot be re-
| used.
|
| If you're familiar with C++11 or later, one way to think of it
| is that `=` in Rust always behaves somewhat like `std::move` in
| C++:
|
| `b = std::move(a);`
|
| The details are substantially different (this will call `a`'s
| move-assignment operator if one exists, which has no equivalent
| in Rust, and C++ offers no support for ensuring that `a` is no
| longer used if its move-assignment operator invalidates it).
| But the general idea that "move semantics are on by default" is
| essentially accurate.
| strictfp wrote:
| Rust is tricky. Took me about a year to grok decently.
|
| Regarding references, the compiler does flow analysis and tries
| to enforce a sort of static rwlock semantic on variable level.
| You either have a single mutable reference xor N readable
| references to the same variable.
|
| If b is a mutable reference to a, c cannot point to a until b
| reliquishes the "lock", which happens when b goes out of scope.
| coldtea wrote:
| > _I don 't understand why b=a; c=a; <-- doesn't work because a
| is "used up"???_
|
| You know how C has a problem with aliases? (multiple variables
| referencing the same thing)? Which introduce bugs, prevent
| optimizations, etc?
|
| Well, Rust tries to prevent this, and make more explicit (and
| known to the compiler) when you do this...
| mikewarot wrote:
| I've only had a passing acquaintance with C and C++, so I've
| never used aliases.
|
| I just googled it... why the heck would you copy pointers?
| That's insane!
|
| In my example, a, b, and c were variables, not pointers.
| coldtea wrote:
| You keep using this word, variables. I don't think it means
| what you think it means.
|
| At least in my book pointers are still variables (as in "a
| pointer variable"), and a variable is any named value,
| whether it's a scalar or a pointer or a nth-pointer, or
| what its storage is.
|
| But you mean that in your example there is no way to affect
| the previous value, right?
|
| > _I just googled it... why the heck would you copy
| pointers? That 's insane!_
|
| Well, copying values and passing them around would be too
| costly on memory (for larger structs especially), and would
| prohibit several techniques.
| mikewarot wrote:
| Variables can be varied... you can increment, decrement,
| do whatever you want with them. They keep track of
| things.
|
| Pointers are used reference things allocated from the
| heap, and never anything else, unless you're insane.
| Pointers get directly handled in linked lists, trees,
| etc.
|
| If at all possible, pointers should be avoided otherwise.
|
| Values passed to a procedure can be done by value (the
| default in Pascal), or by reference (VAR parameters).
|
| I don't see why anyone wouldn't copy values by default...
| it is the only sane way to do things.
| twic wrote:
| > Pointers are used reference things allocated from the
| heap, and never anything else, unless you're insane.
|
| People routinely use pointers to things on the stack in
| several languages. Rust even makes it safe to do that,
| using lifetimes - a pointer to something on the stack
| can't outlive the stack frame it points into.
|
| > I don't see why anyone wouldn't copy values by
| default...
|
| Because not everything is safe to copy. In particular,
| Rust has a few kinds of pointers which come with special
| rules.
|
| Firstly, it has boxes, which always point to something on
| the heap, and have a rule that that when the pointer
| dies, the thing it points to gets freed. If you copied a
| box, then when one of the copies died, the thing would be
| freed, and then the other copy would have a pointer to
| invalid memory, which would be bad.
|
| Secondly, it has mutable references, which come with a
| guarantee that a mutable reference is the _only_ pointer
| to a given thing. If you copied a mutable reference, you
| would break that guarantee.
|
| Thirdly, it has reference-counting pointers (these are in
| the standard library, not the language). You can make
| duplicates of those, but they have to increment their
| reference count when you do so. Copying is always just a
| bitwise copy, so there is no chance to increment the
| reference count. Instead, duplication is an explicit
| operation.
|
| There are a few other things it doesn't make sense to
| copy. Like, what would it mean to copy a mutex?
|
| So, in Rust, you can't copy by default. However, it is
| really easy to mark a type as being copyable (the
| compiler will check that it really is, ie doesn't contain
| any non-copyable things), and then you can copy it.
| coldtea wrote:
| > _Variables can be varied... you can increment,
| decrement, do whatever you want with them. They keep
| track of things._
|
| You can do the same to a pointer in languages that have
| them, either directly (e.g. in C) or through some
| "unsafe" construct (e.g. in Rust, C#, Go).
|
| > _I don 't see why anyone wouldn't copy values by
| default... it is the only sane way to do things._
|
| When resources are ample, yes. Not the case historically,
| or in many use cases today.
|
| And not all values make sense to copy.
|
| But also in Rust, we're talking in the context of C
| performance needs, memory models, and concepts, and Rust
| expands and makes those safe.
| AsyncAwait wrote:
| > Variables can be varied... you can increment,
| decrement, do whatever you want with them.
|
| Variables by themselves are not much. They inherit the
| properties of the type they are bound to. So what you can
| do with them can be as restrictive or as permissive as
| the type allows. That type can be a pointer/reference as
| well.
| AsyncAwait wrote:
| > why the heck would you copy pointers?
|
| Pointer aliasing is not always obvious.
| fasterthanlime wrote:
| It's definitely a lot to take in, you have the right idea --
| the compiler is here to help, the diagnostics are wonderful and
| improving every week thanks to the work of Esteban Kuber and
| others.
|
| Re macros: try to keep an open mind if you can, C macros and
| Rust macros are completely different. You can get very far
| without reaching for them, so don't worry too much!
| k__ wrote:
| _" I don't understand why b=a; c=a; <-- doesn't work because a
| is "used up"???"_
|
| Had the same issue a few months ago.
|
| The pointer can only be referenced by one variable at a time.
|
| If you "move" the pointer from a to b then a is figuratively
| "used up" because a is now blocked from doing anything with the
| pointer anymore.
|
| I guess, for Rust itself the pointer is still referenced by a,
| Rust just blocks you from using it. But thinking you moved it
| to another variable helped me a bit.
| mikewarot wrote:
| if I say
|
| a = 2; b = a; c = a;
|
| There's no pointer in there, just 2.
| rcxdude wrote:
| That will work fine, because 2 is 'Copy', so it can be
| copied trivially (as are structs consisting only of Copy
| members which are marked as Copy). Roughly speaking
| anything with a pointer in it isn't Copy, though many
| objects will implement Clone, which basically just means
| you need to explicitly call .clone() to make a copy instead
| of it happening implicitly.
| mikewarot wrote:
| 2 is Copy? It's an integer, could be 2.0 if you wanted to
| make it a float.
|
| Someone needs to explicitly nail down the mission
| statement of Rust... because to me it seems to be
|
| "Rust will introduce pointers where they don't need to
| be, and then try to protect you from the results with
| obsessive rules"
| AsyncAwait wrote:
| You need to seriously read more on Rust before making
| judgments. You're clearly confused.
|
| What '2 is Copy' means precisely that Rust WILL NOT
| 'introduce pointers where they don't need to be' - 2 is
| fine to 'alias' because it's a primitive type and so a
| copy is made when you do that, (i.e. the type implements
| the 'Copy' trait). However when you do that with complex
| types that do not implement Copy, you're moving ownership
| to the new variable so cannot use the old one any more.
| zRedShift wrote:
| Yes, primitive types all implement Copy.
|
| Maybe playing around with the code would help you better,
| because that last line doesn't make any sense:
| https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
| fasterthanlime wrote:
| I wrote a piece that tries to explain Rust's memory
| management strategy, compared to C:
| https://fasterthanli.me/articles/declarative-memory-
| manageme...
|
| Hope it helps!
| dperalta wrote:
| This is exactly what I need it <3
| timhigins wrote:
| A half-hour to learn Rust Jan 27, 2020 * 51 minute read * rust
|
| maybe the site's reading time estimator is broken? sarcasm
| intended.
|
| But seriously, it is good to have people writing things like
| this.
| stonecharioteer wrote:
| I worked my way through the entire article, typing in each code
| example. Took me about 3 hours.
| oblio wrote:
| Firefox' reader mode estimates it at 35-45, if that helps :-)
| AlchemistCamp wrote:
| > maybe the site's reading time estimator is broken?
|
| All of them are. I first started disliking Medium for just that
| reason.
| keyle wrote:
| Programmers don't read, they skim in half the time, then auto-
| complete in their mind with false assumptions!
| [deleted]
| pjmlp wrote:
| And then try to write a GUI in Rust.
| artursapek wrote:
| The state of that art is improving quickly:
| https://github.com/hecrj/iced
| adwn wrote:
| Maybe the state of the art for _immediate mode GUIs_ ,
| but not everyone is hopping onto that bandwagon.
| pjmlp wrote:
| Doesn't do localization or integration with assistive
| technologies of the host platform, does it?
| artursapek wrote:
| No not yet.
| Fannon wrote:
| Is there a name for this behavior? Sounds like something that
| is categorized as a cognitive bias?
|
| I'm confident that this does not only apply to programmers :)
| coldtea wrote:
| It's the cognitive bias cognitive bias (the idea that every
| random mistaken behavior can be categorized as a congnitive
| bias).
| mariodiana wrote:
| Ouch! And just in time for New Year's resolutions. Thanks!
| brabel wrote:
| That would explain so many of the comments you read on HN and
| Reddit!
| eeZah7Ux wrote:
| > maybe the site's reading time estimator is broken? sarcasm
| intended.
|
| It was not rewritten in rust?
| coldtea wrote:
| > _maybe the site 's reading time estimator is broken_
|
| No, it's just made for prose, not tutorials.
| fasterthanlime wrote:
| Yep, code is a lot of "words" which throws off the estimate.
| I need to address this, but I don't think completely ignoring
| code blocks is really the solution there.
| kangalioo wrote:
| Maybe you could estimate the reading time of a code snippet
| by taking the square root of the number of lines of code? I
| imagine that the larger the code snippet, the more
| irrelevant boilerplate it contains, so the square root
| might be a good way to model this
| internet_user wrote:
| half-hours is only the compilation time.
| fasterthanlime wrote:
| Sarcasm aside, the Rust compiler has gotten a lot faster (and
| parallelizes better) over the last year thanks to Nicolas
| Nethercote and others.
|
| Another thing few people realize is that the "incremental"
| compilation mode that's the default for debug builds can also
| be enabled for release builds!
|
| In CI, something like sccache can help a lot (using the GCS
| or S3 backend). It makes GitHub Actions' two-core limit
| almost bearable. Almost.
| pwdisswordfish6 wrote:
| Per snippet.
| swazzy wrote:
| I'm guessing the code snippets are skewing the estimate.
| mraza007 wrote:
| Literally the most easiest way to understand Rust.
|
| Just want to take a moment a appreciate your efforts for writing
| this amazing article. Honestly it made it so easier to understand
| Rust especially for a beginner like me
| baby wrote:
| Usually I would recommend learnXinYminutes.com for that
| archon wrote:
| Preface: This is an honest question, not an attempt to start a
| "which language is better" war.
|
| I'm proficient in C#. I haven't yet encountered any problems I
| can't solve with C# and the .Net open source ecosystem. (Perhaps
| that says more about the banality of the problems I'm solving
| than about .Net, but there you are.)
|
| What would Rust give me the tools to do that I can't already
| accomplish with C# / .Net Core?
| damnyou wrote:
| Control over 95th+ percentile latency.
| emrah wrote:
| Rust is a systems (i.e. lower level) language similar to C and
| C++ that can be compiled to native standalone executables.
|
| If you're primarily doing app dev work, be it desktop or web,
| you wouldn't really benefit much from it. Although I think Rust
| code can be compiled to wasm so you could use it as part of
| webdev work.
|
| You might also find this an interesting read from the same
| author: https://fasterthanli.me/articles/i-am-a-java-csharp-c-
| or-cpl...
| oddx wrote:
| Predictable (low) pauses. Ability to (easily) embed into other
| language/app as library/plugin.
| Barrin92 wrote:
| >In this article, instead of focusing on one or two concepts,
| I'll try to go through as many Rust snippets as I can
|
| I really like this. One of the things I like to do when learning
| a new language is to go to
| http://www.rosettacode.org/wiki/Rosetta_Code and just go through
| snippet examples for certain common tasks.
|
| Just quickly going through examples to me feels much easier than
| trying to learn from principles.
| skc wrote:
| This is actually fantastic.
|
| Wish more language tutorials were exactly like this, no fluff.
| Sander3Utile wrote:
| Here is another similar resource for learning new programming
| language's on the fly
|
| https://learnxinyminutes.com/
| Animats wrote:
| That is the best article on Rust I've ever seen. Better than the
| Rust book. I've been saying that Rust needed a book that wasn't
| written by the designers of the language, who are too close to
| it. Now we have one.
| Xunjin wrote:
| Rust Crash Course by Michael Snoyman is great. You can get a
| free copy at fpcomplete.
|
| Did a free course in December with him, and I'm still watching
| the classes because it has so much great info there.
|
| Also I do recommend the Rust Programming, it really teaches you
| "how/why" use Rust.
|
| To conclude, rust-learning (at GitHub) have great links,
| amazing articles about parts of the language, there is so much
| knowledge there, just go collect it :P
| nobleach wrote:
| Link for those interested:
| https://www.snoyman.com/blog/2018/10/introducing-rust-
| crash-...
| nobleach wrote:
| I'd LOVE it if we could get a Why's Poignant Guide To Rust... I
| find that kind of weird humor helps my mind remember things.
| christiansakai wrote:
| This article is very very basic beginner Rust. You'll be
| disappointed if you expect to encounter Rust in real world like
| this article.
| [deleted]
| jjice wrote:
| Out of curiosity, what don't you like about the Rust book? I
| personally loved it, reading about a year and a half ago. I
| thought they covered most of what I needed, was well written,
| and had plenty of good examples.
| steveklabnik wrote:
| Not all writing clicks with every reader, it is impossible.
|
| He previously said "That's too hard for an introductory book
| and not detailed enough for a reference manual." It is _very_
| difficult to get this right, given our goals, and so
| reasonable people may think we fall short there.
| dbaupp wrote:
| You may be also interested in the many existing teaching
| resources published by non-language-designers (whatever that
| means for a community-driven project like Rust), such as
| Rustlings and Rust by Example at https://www.rust-
| lang.org/learn if the book doesn't satisfy whatever criterion
| you think disqualify it. Some of it is published via the rust-
| lang.org website, but it was/is maintained by different people
| who work on the language, compiler, std lib (etc). The project
| has a large number of people across many teams:
| https://www.rust-lang.org/governance
| timClicks wrote:
| There are a few other well regarded resources. _Programming
| Rust_ from Blandy, Orendorff, and Tindall /O'Reilly is great if
| you have lots of knowledge in C/C++. _Rust in Action_ from
| McNamara /Manning is great if you prefer to learn by building
| projects.
|
| Disclaimer: am the author of Rust in Action
| tgv wrote:
| But it only covers the very basics. Disclaimer: I've only
| scrolled through it, but the code snippets are all small. It
| does show an admirable amount of Rust's syntax, but it's not
| very discoverable, whereas the book is reasonably well
| structured (although not for novices, who have forgotten a
| specific term). The link also doesn't deal with larger
| programs: there's not an Rc<T> on the page, let alone something
| like an Arena and unsafe code, and it's really necessary for
| complex programs.
|
| So, IMO: not better than the Rust book. It gives a first glance
| of Rust, something to accustom the eyes to a different syntax,
| but sidesteps the difficult bits, which can make transitioning
| so frustrating.
| Aeolun wrote:
| I don't think you should have much unsafe code as a rust
| beginner.
| trumpeta wrote:
| There are plenty of cases where you can write a complex
| program in Rust without ever needing those things.
| lordnacho wrote:
| I've favourited the article. It's a good complement to the
| Rust Book, which has more detail. This kind of summary doc is
| great for discovery, you skim it and you find something that
| you could have written differently, or you realise there's an
| idiom you weren't using.
|
| No substiture for the book, though.
| fasterthanlime wrote:
| I have a _lot_ of Rust articles[1] that go into a lot more
| depth. They 're mostly adventures though, we learn about
| ICMP, ELF, file systems etc.
|
| Some love that style (the detours, the stream of
| consciousness) and some can't stand it. The Rust book is
| excellent, and a completely different style -- they're
| complementary!
|
| [1]: https://fasterthanli.me/tags/rust
| EugeneOZ wrote:
| It's your opinion and I'm not arguing: a lot of people love
| the Rust book, but some (including me) simply can't read it
| because of the style of writing and cases when you discover
| some interesting and deep topic but the author just gives 1
| example in 5-10 lines of code and that's all. I think that
| things like Mutexes or Boxes are deep enough to have 30-50
| pages dedicated to them, and I can say this not only about
| Mutexes and Boxes. When explaining some powerful things, one
| need not only explain how they work, but also what kinds of
| real tasks they can solve - ways of usage are obvious for you
| when you know it and have experience of usage them, but
| absolutely opaque and not obvious when you reading about them
| for the first time.
| ibraheemdev wrote:
| I highly recommend Jon Gjenset's streams for more advanced
| Rust concepts like lifetimes or interior mutability. He
| goes into depth explaining how they work, what kinds of
| problems they solve, and gives tons of great examples.
| nindalf wrote:
| > And here's a toilet closure: |_| ()
|
| > Called thusly because |_| () looks like a toilet.
|
| Pure poetry!
|
| Real talk though, this is a great introduction.
| jerrre wrote:
| I've been staring at this for a minute, but please help me
| seeing a toilet in this? Is it a top down view perhaps?
| kyrrewk wrote:
| toilet seat up
| jackric wrote:
| which bit is the toilet seat?
| AlexSW wrote:
| The seat is to the right (the ( )) and the water tank (?)
| is on the left.
| matt_kantor wrote:
| I made a visual: https://i.imgur.com/VgsDidE.jpg
| CJefferson wrote:
| I often use the "owl" <(),()>, usually in Result<(),()>.
| brabel wrote:
| Why use a Result whose error type is empty?
| CJefferson wrote:
| I should have said :) I am writing backtracking algorithms
| (think something like a Sudoku solver where we fill in
| values by guessing), and an 'Error' is when we can deduce
| the Sudoku cannot be filled in, so we have to backtrack.
|
| I find Rust's ? notation gives a very natural way of
| writing such algorithms. I don't care "why" filling in the
| Sudoku failed, particularly because the solver will
| typically fail millions of times a second, so I definately
| don't want constructing the error to be expensive in any
| way.
| jackric wrote:
| I would suggest Option is the more semantic type to use
| for your situation - None indicating no valid solution on
| this path
| CJefferson wrote:
| Oh, today I learned the ? operator works with Option as
| well as Result! I might try that out, thanks.
| cesarb wrote:
| IIRC, it didn't work with Option in the past, so you
| might have been correct when your code was written. The ?
| operator came originally from the try!() macro, which was
| specific to Result; unlike the macro, it was designed to
| be extensible through the still-unstable std::ops::Try
| trait, but IIRC that trait was initially implemented only
| for Result, and only later was extended to Option and a
| couple of others.
| l00sed wrote:
| I've mostly used web-specialized programming languages like
| JavaScript and PHP, and some Python. Some of the unique
| characteristics of Rust have been trickier for me to pick up.
|
| This looks like a fun and useful article, but I'd also recommend
| Rustlings to anyone interested in learning Rust.
|
| https://github.com/rust-lang/rustlings
| IshKebab wrote:
| This is very good although the title definitely promises too
| much!
| redisman wrote:
| There wasn't anything on concurrency or asynchronous programming
| (like a http client). Is there a good resource for those parts of
| the language?
| fasterthanlime wrote:
| The closest I've written is this:
| https://fasterthanli.me/articles/getting-in-and-out-of-troub...
| but it explicitly seeks the complicated bits because
| elucidating those is the whole point of the article.
|
| I might write another one that focuses on the happy path.
| akavel wrote:
| Newbie question: in the last example: fn
| make_tester(answer: &str) -> impl Fn(&str) -> bool + '_ {
| move |challenge| { challenge == answer }
| }
|
| why is there `move` needed, if both `answer`, and the arg of
| `Fn`, seem to be references (`&str`)? To a layman, this sounds
| like as if both "challenge" and "answer" should be borrowed - so
| why "move"? what's even to move here?
| steveklabnik wrote:
| I _believe_ what happens here is that the closure tries to
| capture it as a &&str. This is because it defaults to trying
| to take the environment by reference. The "move" in this case
| means that it will try to take it by value instead. This feels
| tricky semantically because references are types too, so
| "taking it by value" means taking a &T rather than a &&T, just
| like you may think about how taking a T is by value as opposed
| to &T.
| ridiculous_fish wrote:
| This is confusing, and Rust's error messages make it much
| worse. If you try to remove the `move`, you get an error:
|
| > closure may outlive the current function, but it borrows
| `answer`, which is owned by the current function. To force the
| closure to take ownership of `answer` use the `move` keyword.
|
| But 'answer' is of course not owned by the current function,
| and how can you take ownership through a shared reference?
|
| The explanation is double indirection. By default, the closure
| captures a pointer to answer, which is itself a pointer on the
| stack. Without the 'move', inside the closure `answer` has type
| &&str and points into make_tester's stack frame. With the
| 'move', it copies the passed-in pointer. The error message is
| referring to the pointer itself, and this is not obvious.
|
| Incidentally I have never found docs for the '+' syntax there,
| would appreciate a pointer to any.
| steveklabnik wrote:
| The + syntax is https://doc.rust-
| lang.org/reference/types/trait-object.html#...
|
| This applies to impl Trait as well. It should probably be
| there too...
| ridiculous_fish wrote:
| Thanks!
| Rotten194 wrote:
| Iirc it's moving the reference to answer, not the value.
| momothereal wrote:
| In this closure you are moving `answer`, that is, you are
| moving the reference itself into scope. The `challenge`
| reference is already owned by the closure since it's a
| parameter. The move doesn't mean the closure owns the
| underlying strings, but the references themselves.
| mkl95 wrote:
| I like Derek Banas' approach. He makes introductory videos for
| several languages.
|
| They are suited for developers who already have some experience
| in another language, and they last from 45 minutes to 2 1/2
| hours.
|
| https://www.youtube.com/watch?v=U1EFgCNLDB8
| Tade0 wrote:
| There's a lot of valuable, condensed knowledge here, but for
| those who wish to learn the language in a more interactive way I
| recommend Rustlings:
|
| https://github.com/rust-lang/rustlings
|
| I spent the last two weeks going through it and so far the
| experience has been great. There's a quiz at the end of most
| chapters.
| miccah wrote:
| I have been learning rust interactively with Exercism, which
| uses a mentor system to provide feedback and suggestions.
|
| https://exercism.io/tracks/rust
|
| It's also great to view other learner's solutions once you
| complete the exercise.
| noisy_boy wrote:
| I have been doing the rustlings exercises (which are basically
| exercises to fix errors on various topics) - they are just the
| right size to keep you engaged and continuing because they
| reward you with success. Also its very easy to leave it
| anywhere and resume exactly the same point or go back to an old
| exercise and retry it. Plus because its just code organized in
| a directory, you can leverage all the feature of your favorite
| IDE. Highly recommended.
| bbx wrote:
| In similar fashion you can learn "Web Design in 4 minutes" [1]
| and "JavaScript in 14 minutes" [2]
|
| [1] https://jgthms.com/web-design-in-4-minutes/
|
| [2] https://jgthms.com/javascript-in-14-minutes/
| dnautics wrote:
| I spun up a roughly equivalent version of this for Zig, I would
| say this is about 70% of the language:
|
| https://gist.github.com/ityonemo/769532c2017ed9143f3571e5ac1...
| techolic wrote:
| let x; foobar(x); // error: borrow of possibly-
| uninitialized variable: `x` x = 42;
|
| possibly-uninitialized - Why does the compiler sound uncertain
| while emitting an error?
| steveklabnik wrote:
| The analysis is not perfect. It's worded that way to
| acknowledge this fact.
|
| It also is language that works well when something may be
| initialized in some control flow paths but not all.
| ibraheemdev wrote:
| I was inspired by this article and wrote "Twenty minutes to learn
| Go" [0]. Go being a much simpler language than Rust, I feel that
| anyone who knows a programming language can become productive in
| Go in less than an hour. Of course this simplicity comes at the
| cost of increased boilerplate, less expressiveness...
|
| 0: https://ibraheem.ca/posts/go-in-twenty
| inancgumus wrote:
| [dup] duplicate https://news.ycombinator.com/item?id=22448933
| dmitshur wrote:
| For anyone curious what a Go version of the same article would
| look like (as I was), I tried to answer that question by writing
| https://dmitri.shuralyov.com/blog/27.
| dnautics wrote:
| thanks for inspiring me, I did one for zig as well:
|
| https://gist.github.com/ityonemo/769532c2017ed9143f3571e5ac1...
| faitswulff wrote:
| I enjoyed this, thank you!
| walkingolof wrote:
| Comments like this are to far in-between on the internet,
| kudos!
| mojuba wrote:
| (Side note: dear Apple, please add syntax coloring and code
| formatting for Rust to Xcode. You have Fortran and C Shell in the
| list, but not Rust or Go, which are much more popular!)
| speedgoose wrote:
| Is there any reason to use Xcode for Rust development?
| mojuba wrote:
| It's a habit. Keyboard shortcuts, familiar bugs and glitches,
| etc are not easy to change.
| [deleted]
| elvongray wrote:
| Reminds me of this also: https://cheats.rs/
| dmurray wrote:
| Great article.
|
| I've never used Rust before so I'm exactly the target audience. I
| first got tripped up around
|
| > Trait methods can also take self by reference or mutable
| reference: impl std::clone::Clone for Number {
| fn clone(&self) -> Self { Self { ..*self } }
| }
|
| What's the asterisk doing in this code? I guess it's
| destructuring the struct somehow, but I don't see that syntax
| elsewhere: destructuring was introduced but looked like it worked
| without the star. Alternatively, it's dereferencing the
| reference, but that seems less likely.
| pornel wrote:
| It is dereferencing. It changes `&self` to `self`. The `..`
| operator wants a value, not a reference.
| Aeolun wrote:
| So the & and * can basically be left out to make 'self' a
| value from the start?
| rcxdude wrote:
| technically yes, but it'll change the semantics in a not
| useful way. Because if you leave off the & on self then the
| method won't borrow self (take it by reference) but consume
| it (take it by value by 'moving' it), so you can't use it
| any more after calling clone(), which basically makes the
| method a no-op instead of copying the struct.
| dmurray wrote:
| Thanks pornel and rcxdude, this makes sense to me now. I
| was thinking it shouldn't be dereferencing because when
| references were previously introduced (the print_number
| example), we could call methods on the reference without
| any special syntax. But I guess it makes sense that
| instance methods work that way, while other functions
| need to know if we have a reference or the real object,
| and in this regard it works more or less like C++.
| st1x7 wrote:
| I also find some of the syntax peciliarities and their
| combinations difficult to look up. In addition to & and *,
| there's question marks, dots, double dots,
| square/round/triangle brackets, empty parentheses and
| apostrophes all over the place and it makes it really difficult
| to deconstruct what's happening in a block of code.
| runjake wrote:
| I like to use LearnXInYMinutes as my first stop for learning a
| new language.
|
| Often, I end up being able to get started right away, but at
| worst, it gives me an accelerated start into tougher cookies like
| Rust.
|
| https://learnxinyminutes.com/
___________________________________________________________________
(page generated 2021-01-02 23:01 UTC)