6 ms·
As a Rust newbie, how do I learn how to read this? pub struct Stream<'s, S: Seed, A: Copy> { next: Box<dyn Fn(S) -> Step<S, A> + 's>, seed: S }
by Tempest1981 6y ago
As a Rust newbie, how do I learn how to read this?
pub struct Stream<'s, S: Seed, A: Copy> {
next: Box<dyn Fn(S) -> Step<S, A> + 's>,
seed: S
}
Can someone summarize in a sentence or two? Or point to some docs?
- steveklabnik 6y agoI read this as "there is a public struct named Stream that takes one lifetime parameter and two type parameters. There are two members, a seed, and a next closure that takes a seed, and returns some iterator which gives a new seed and a value." That doesn't fully describe all of it, and there's some inferences there, but that's how I hear it in my head. Some of it is experience, and some of it is context, too. Especially that "an iterator" part. I'd expect to see Iterator when talking about iterators, but the 'shape' for a lack of a better word looks like one to me. Rust's syntax is pretty regular and modular. After some practice, the bits start to fit together, and the way to tackle more complex signatures is the same as how you tackle complex code: break it up into smaller bits, and then assemble your understanding of the bits.
- andrewzah 6y agohttps://doc.rust-lang.org/stable/rust-by-example/std/box.html https://doc.rust-lang.org/stable/rust-by-example/std/box.htm... https://doc.rust-lang.org/book/ch10-02-traits.html https://doc.rust-lang.org/book/ch10-02-traits.html https://doc.rust-lang.org/book/ch17-02-trait-objects.html https://doc.rust-lang.org/book/ch17-02-trait-objects.html https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.html https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.h... https://stackoverflow.com/questions/47640550/what-is-a-in-rust-language/47641166 https://stackoverflow.com/questions/47640550/what-is-a-in-ru... https://doc.rust-lang.org/book/ch10-00-generics.html https://doc.rust-lang.org/book/ch10-00-generics.html
- dochtman 6y agoStream is a struct (a type with named fields). It has three parameters, the lifetime s, the type S and the type A. S must satisfy the Seed trait, and A must satisfy the Copy trait. Stream has two fields, next and seed. The type of next is a Box (basically an owned pointer into the heap) of a type that implements the Fn(S) -> Step<S, A> interface (that is, it can be called with an S as the single argument and produces something of the type Step parametrized with S and A) and does not outlive the s lifetime. The field seed is of the type S. This chapter of the book is probably a good start: https://doc.rust-lang.org/book/ch10-00-generics.html https://doc.rust-lang.org/book/ch10-00-generics.html
- partiallattice 6y agoSmall typo: it can be called with an S as the single argument and produces something of the type Step parametrized with S and A) and -does not- outlives the s lifetime. 's refers to a minimal lifetime and not a maximal limit.
- vaylian 6y agoThat's a fairly complicated example. Let me deconstruct it: In Rust you work a lot with types. You can write code that supports several different types but you usually have to specify which constraints these types have to fulfill. You specify these constraints between <> brackets. In this example we have 3 such constraints: 1) <'s, S: Seed, A: Copy> 2 & 3) <dyn Fn(S) -> Step<S, A> + 's> with 2) <S, A> with 3) <dyn Fn(S) -> Step<S, A> + 's> Because these constraints are all part of the same struct definiton, the names in these 3 constraints refer to the same things. The names are: s, S, A Constraints in Rust can either be lifetimes or traits (similar to interfaces in Java). Lifetimes are marked with a single quote (') followed by the name of the lifetime (in this case: 's) Let's look at constraint number 1): I) We declare a lifetime 's but we do not specify where it will be applied in the struct yet. II) We declare a type constraint S. Every type that is used as S must implement the Seed trait. III) We declare a type constraint A. Every type that is used as A must implement the Copy trait. Before I go into constraint 2&3, I must explain that `Fn(S) -> Step<S, A> + 's>` describes the type signature of a closure. The syntax is basically `Fn(parameter-list) -> return-value`. Constraint 2) says that the return value must be a struct `Step` with the type parameters `S` and `A`. Constraint 3) says that the next field of the struct must be a `Box` that contains an object of unknown size (hence the `dyn`) which is a closure that takes one `S` parameter and returns a `Step` struct with the type parameters `S` and `A`. The lifetime of the closure must be `'s`. Finally, the seed must be of type `S`.
- gameswithgo 6y agothe good news is that is a worst case scenario and pretty rare
- willwinger 6y agoI have been using Rust for my side project https://github.com/elasmojs/rooster https://github.com/elasmojs/rooster Rust is just great! I feel liberated from Java and Node. But what intrigues me is why do programmers insist on making code look and feel difficult? Is there a secret obsession in good programmers to make their code look clever? Is variable naming not a basic etiquette?
- mplanchard 6y agoHow would you approach the naming of this example differently? I have gone back and forth on whether to align with the general convention on single-letter generic type names, but I’ve tended to come back to the single-letter approach any time I try making them more specific. The issue is of course that they are generic, and so naming them too explicitly robs them of some of their “this is any type” genericness. For lifetimes, I will definitely sometimes name them more explicitly than `’a`, but usually only when there’s more than one, as a way of being sure I don’t mix them up. However, the association of lifetimes with references tends to be straightforward enough that it often seems clearer and less messy to just name them with single characters.
- willwinger 6y agoI understand but in this case we have the lifetime as s, seed as S and copy as A. And you can see how it creates that extra effort for someone who is seeing it for the first time. For me any code is associated with its application and that application should be evident in the code. We talk a lot about user experience and usability in our end products but we do not extend that thought to our fellow programmers at code level.
- SAI_Peregrinus 6y agoI don't mind single-letter names, but I dislike having the same letter used with different case for two different names. In this example I'd probably have a lifetime 'l, a seed S, and a copy C. That way there's no "s" vs "capital s" confusion when saying what the names are.