Skip to content
This repository has been archived by the owner on Sep 30, 2020. It is now read-only.

Added Frequently Asked Questions Page #202

Closed
wants to merge 42 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9d80dad
Added FAQ
Sep 1, 2015
bea69ad
Updated FAQ
Oct 22, 2015
596d92c
Cleanup
Oct 22, 2015
a532931
Corrections
Oct 23, 2015
b782659
Updated FAQ based on Diggsey's suggestions
Oct 24, 2015
e94751d
Addressing feedback
Nov 6, 2015
9646f3f
More corrections
Nov 15, 2015
756a5d2
Added answer for Rust versioning
Nov 15, 2015
2aad0da
Add another answer
Nov 15, 2015
a3c9d13
Mobile style improvements
Nov 15, 2015
5f458fb
Removed copyright notice
Nov 18, 2015
5c1409b
Removed list of companies using Rust
Nov 18, 2015
5a66ed8
Some additional cleanup and review
Nov 18, 2015
dbd997b
Organized sections
Nov 18, 2015
57f72c5
Simplified CSS
Nov 18, 2015
d718d7c
Updating answers
Nov 20, 2015
57f62ac
Addressed latest round of feedback
Dec 16, 2015
fabd2ba
Take a pass over the whole FAQ
brson Dec 20, 2015
8b3265f
Fix alignment of operator table in FAQ
brson Dec 20, 2015
dc0774d
Merge pull request #1 from brson/faq
AndrewBrinker Jan 3, 2016
0ef5d23
Fixed typos
Jan 3, 2016
9da71ec
Updated answer about higher-kinded type support
Jan 3, 2016
20c365f
Clarified answer on Ord/PartialOrd and Eq/PartialEq split
Jan 3, 2016
095d45c
Updated borrow checker answer
Jan 3, 2016
7721973
Typo fixes
Jan 3, 2016
435b1de
Addressed charlotteis' suggestions
Jan 3, 2016
601a473
Small fixes
Jan 3, 2016
ef9715a
Changed to 4-space indent in code samples
Jan 3, 2016
123c803
Updated based on tshepang's latest feedback
Jan 4, 2016
1c3a038
More corrections based on tshepang's feedback
Jan 4, 2016
3425bdd
Integrated latest feedback from tshepang
Jan 4, 2016
c374cbb
First pass with new feedback
Jan 7, 2016
7ba7f3d
New draft of the higher-kinded types answer
Jan 8, 2016
e7bab64
Partial addition of API doc links
Jan 8, 2016
1594ab3
Fixed based on feedback from pnkfelix
Jan 8, 2016
ffb11a7
Small correction
Jan 8, 2016
ea304ed
Updated based on latest feedback
Jan 9, 2016
8e490bb
Updated ord/eq answers
Jan 9, 2016
6705771
Updated borrow checker answer
Jan 9, 2016
6b75c04
Updated lifetime elision answer
Jan 9, 2016
c4e41f0
Fixed typo
Jan 9, 2016
898dd0f
Added links to API docs
Jan 9, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Corrections
  • Loading branch information
Andrew Brinker committed Oct 23, 2015
commit a5329311227a403b82bffab7e4208e71e228b1b6
50 changes: 37 additions & 13 deletions faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,13 @@ In general, tail-call optimization is not guaranteed: see [here](https://mail.mo

#### Does Rust have a runtime?

Rust has a [very small and limited runtime](https://github.com/Kimundi/lazy-static.rs) providing a heap, unwinding and backtrace support, and stack guards. This runtime is comparable to the [C runtime](http://www.embecosm.com/appnotes/ean9/html/ch05s02.html), and allows for the calling of Rust functions from C without setup.
Rust has a [very small and limited runtime]() providing a heap, unwinding and backtrace support, and stack guards. This runtime is comparable to the [C runtime](http://www.embecosm.com/appnotes/ean9/html/ch05s02.html), and allows for the calling of Rust functions from C without setup.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[very small and limited runtime]() no link here?


## Concurrency
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like there are more concurrency questions that should be listed here. For example, I frequently hear people express surprise that Rust supports mutexes, since early versions of the language supported only message passing. Perhaps a question explaining this would make sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy to add some more concurrency questions and answers. The included answers right now are a combination of topics covered in previous FAQs (updated, of course) and questions suggested after soliciting input from the community. It may simply be that a second round of question seeking may be in order, with particular focus on concurrency and any other sections currently under-covered by the FAQ.


#### Can I use globals across threads without `unsafe`?

No, even if the type implements `Sync`.

Types which are `Sync` are thread-safe when multiple shared references to them are used concurrently. Types which are not `Sync` are not thread-safe, and thus when used in a global require `unsafe` to use.

That being said, having multiple aliasing `&mut T`s is never allowed. Due to the nature of globals the borrow checker cannot possibly ensure that a `static` obeys the borrowing rules, so taking a mutable reference to a `static` is always unsafe.
Yes, if the type implements `Sync`, doesn't implement `Drop`, and you don't try to mutate the global value.

## Error Handling

Expand Down Expand Up @@ -201,6 +197,10 @@ fn example2<'a>(s: &'a str) -> &'static str {

The problem with declaring the lifetime as `static` is that it's rarely what you actually mean, and is instead a way of escaping the lifetime system. References with a `static` lifetime outlive everything else, and this means that they can be used in ways that would otherwise be invalid with the first method.

An alternative is to return an owning type like `String`. This eliminates the reference issues entirely, at the cost of possibly unnecessary allocations.

There is also the `Cow` ("copy on write") type, which will only do the extra allocation if you attempt to mutate the contained value.

#### How do I return a closure from a function?

To return a closure from a function, it must be what's called a "move closure", meaning that the closure is declared with the `move` keyword. As [explained in the Rust book](https://doc.rust-lang.org/book/closures.html#move-closures), this gives the closure its own stack frame, so it is not dependent on its parent stack frame. Otherwise, returning a closure would be unsafe, as it would allow access to variables that are no longer defined (put another way, it would allow reading potentially invalid memory). The closure must also be wrapped in a `Box`, so that it is allocated on the heap. Read more about this [in the book](https://doc.rust-lang.org/book/closures.html#returning-closures).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • "what's called" is unnecessary because "move closure" is in quotes.
  • "so it is not" -> "so that it is not"?
  • "dependent" -> "dependant"
  • "parent stack frame" -> "parent's stack frame"?
  • "no longer defined" -> 'alive' or 'valid' instead of defined?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"its own stack frame" doesn't sound right. A closure could be allocated on the heap too. I would rephrase this as "gives the closure its own copy of the captured variables,independent of its parent stack frame".

Expand Down Expand Up @@ -240,7 +240,7 @@ At the moment, you can't without `unsafe`. If you have a struct with a pointer t

#### What is the difference between consuming and moving/taking ownership?

Consuming means that the value has been dropped, and is no longer defined. With just a move, the value is still alive, but ownership has been transferred to a new owner, meaning the old owner can no longer modify it or lend out references.
These are different terms for the same thing. In both cases, it means the value has been moved into a function, and moved out of the calling owner.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved into a function

Might be worth rewording, since ownership transfer can happen in places other than function calls.


#### Why when I pass a struct to a function the compiler says it's been moved and I can't use it anymore, when the same doesn't happen for integers?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heading is a bit jarring to read, although I'm not entirely sure about alternatives...

  • "Why can I use integers after I've passed them to a function, but can't use structs?"
  • "Why do I never get "use of moved value" with integers?"


Expand Down Expand Up @@ -292,7 +292,7 @@ Things stabilize all the time, and the beta and stable channels update every six

#### How can I convert a `String` or `Vec<T>` to a slice (`&str` and `&[T]`)?

Using Deref coercions! `Strings` and `Vec`s will automatically coerce to their respective slices when referenced.
Using Deref coercions `Strings` and `Vec`s will automatically coerce to their respective slices when passed by reference with `&` or `& mut`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Period (or comma) after "Using Deref coercions"?

Maybe example code here too?


#### How can I convert from `&str` to `String` or the other way around?

Expand Down Expand Up @@ -337,7 +337,7 @@ let v: Vec<&str> = s.lines().collect();

#### How do I do O(1) character access in a `String`?

You don't, not without converting the `String` into something else. If you do that, it comes with some serious caveats. Strings in Rust are all UTF-8 encoded, and O(1) access to characters is impossible in UTF-8. If you index by bytes as you normally would in ASCII strings you'll get a UTF-8 codepoint, which may or may not be an actual character.
`str` implements both the `Index` and `IndexMut` traits, but because Rust strings are all UTF-8, and so it can be indexed exactly as you would expect. But if you do that, it comes with some serious caveats. Strings in Rust are all UTF-8 encoded, and O(1) access to characters is impossible in UTF-8. If you index by bytes as you normally would in ASCII strings you'll get a UTF-8 codepoint, which may or may not be an actual character. If you try to index a location that is not a valid UTF-8 boundary, the operation with panic, which makes it doubly unlikely that indexing is what you're looking for.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First sentence sounds wrong.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

str implements indexing by a range, which yields substrings. Getting chars by byte index is not currently supported (if you ignore the unstable char_at and the very roundabout s[i..].chars().next()). It seems to me like this whole answer is more likely to confuse than to be helpful. It assumes a lot of knowledge about text processing and at the same time is imprecise about it (what's a "character" anyway?).


If you are absolutely certain your string is in fact ASCII, you can get O(1) access by indexing the underlying buffer like so:

Expand All @@ -359,7 +359,7 @@ Scanning a `str` for ASCII-range codepoints can still be done safely octet-at-a-

Most "character oriented" operations on text only work under very restricted language assumptions sets such as "ASCII-range codepoints only". Outside ASCII-range, you tend to have to use a complex (non-constant-time) algorithm for determining linguistic-unit (glyph, word, paragraph) boundaries anyways. We recommend using an "honest" linguistically-aware, Unicode-approved algorithm.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • "very restricted language assumptions sets" -> "very restricted language assumptions,"?
  • "anyways" -> "anyway"?


The `char` type is UCS4. If you honestly need to do a codepoint-at-a-time algorithm, it's trivial to write a `type wstr = [char]`, and unpack a `str` into it in a single pass, then work with the `wstr`. In other words: the fact that the language is not "decoding to UCS4 by default" shouldn't stop you from decoding (or re-encoding any other way) if you need to work with that encoding.
The `char` type is UTF32. If you honestly need to do a codepoint-at-a-time algorithm, it's trivial to write a `type wstr = [char]`, and unpack a `str` into it in a single pass, then work with the `wstr`. In other words: the fact that the language is not "decoding to UTF32 by default" shouldn't stop you from decoding (or re-encoding any other way) if you need to work with that encoding.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/honestly need to do/are sure you need/? I think "honestly" sounds a bit accusatory.


## Collections

Expand Down Expand Up @@ -565,6 +565,10 @@ There are a couple developing options: [RustDT](https://github.com/RustDT/RustDT
- There is no global inter-crate namespace; all name management occurs within a crate.
- Using another crate binds the root of its namespace into the user's namespace.

#### Why can't the Rust compiler find this library I'm `use`ing?

There are a number of possible answers, but a common mistake is not realizing that `use` declarations are _always_ relative to the crate root. Try rewriting your declarations to use the paths they would use if defined in the root file of your project and see if that fixes the problem.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to mention how self and super change this behaviour.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth mentioning the use ::foo syntax.


#### Why do I have to declare module files with mod at the top level of the crate, instead of just `use`ing them?

There are two ways to declare modules in Rust, inline or in another file. Here is an example of each:
Expand Down Expand Up @@ -663,6 +667,8 @@ Over time more and more answers will be offered for the current version, this im

Monomorphisation is the process by which Rust generates specific instances of a generic function based on the types of the various calls to that function. This is used to provide static dispatch for generic functions. For functions using trait objects for generics, dynamic dispatch is used instead, with calls to the function going through a vtable to identify specific function calls for the provided type implementing the given trait.

In C++ people would likely know this as "template instantiation." But unlike C++, Rust's monomorphisation is an implementation detail, and not a language feature.

#### What's the different between a function and a closure that doesn't capture any variables?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

difference


Functions are a built-in primitive of the language, while closures are essentially syntactic sugar for one of three traits: `Fn`, `FnMut`, and `FnOnce`. When you make a closure, the Rust compiler automatically creates a struct implementing the appropriate trait of those three and containing the captured environment variables as members, and makes it so the the struct can be called as a function.
Expand Down Expand Up @@ -921,9 +927,9 @@ Rust doesn't currently have an equivalent to template specialization, but it is

#### How does Rust's ownership system related to move semantics in C++?

In C++, moving vs copying was added on late with C++11. With Rust the concept of moving vs copying has been around from the beginning. In C++ something can be moved into a function or out of a function using r-value references and either `std::move` or `std::forward`. In Rust, moves happen for anything that does not implement the `Copy` trait (which will cause the value of the type to be copied, rather than moved). This means that moves are the default operation, and that copies must be opted into explicitly.
In C++, moving vs copying was added on late with C++11. With Rust the concept of moving vs copying has been around from the beginning. In C++ something can be moved into a function or out of a function using r-value references and either `std::move` or `std::forward`. In Rust, moves happen for anything that does not implement the `Copy` trait (which will cause the value of the type to be copied, rather than moved). This means that moves are the default operation, and that copies must be opted into explicitly. It's also important to know that moves in Rust are destructive copies, which call `Drop` (equivalent to a C++ destructor) on the moved value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also important to know that moves in Rust are destructive copies, which call Drop (equivalent to a C++ destructor) on the moved value.

But they don't! A moved-out variable in Rust simply becomes uninitialized memory. There is nothing left to drop.
This is in contrast to C++, btw, where move must leave behind a valid value, because its destructor will be called at the end of the scope. This forces some types to define a dummy value in order to be move'able. See e.g. std::thread.


One thing to note, however is that moves are often not necessary or desirable in Rust. If the function you're writing does not require ownership of the value being passed in, it should probably be borrowed (mutably or immutable, as necessary) rather than moved or copied.
Moves are often not necessary or desirable in Rust. If the function you're writing does not require ownership of the value being passed in, it should probably be borrowed (mutably or immutably, as necessary) rather than moved or copied.

It's also useful to note that functions can explicitly require that an input parameter be copied like so:

Expand All @@ -939,7 +945,25 @@ The simplest way is to interoperate through C. Both Rust and C++ provide a [fore

#### Does Rust have C++-style constructors?

No. Functions can serve the same purpose as constructors without adding any language complexity.
No. Functions can serve the same purpose as constructors without adding any language complexity. The usual name for the constructor-equivalent function in Rust is `new()`, although this is just a social norm rather than a language rule. The `new()` function in fact is just like any other function. An example of it looks like so:

```rust
struct Foo {
a: i32,
b: f64,
c: bool
}

impl Foo {
fn new() -> Foo {
Foo {
a: 0,
b: 0.0,
c: false
}
}
}
```

#### Does Rust have copy constructors?

Expand Down