Check out a free preview of the full Rust for TypeScript Developers course
The "Numbers & Strings" Lesson is part of the full, Rust for TypeScript Developers course featured in this preview video. Here's what you'd learn in this lesson:
ThePrimeagen explains how Rust handles Number and String types. Rather than a single Number type, Rust has types representing integers, unsigned integers, and floating point numbers. Strings can be represented by a mutable String type or an immutable &str, a pointer to a sequence of utf-8 characters.
Transcript from the "Numbers & Strings" Lesson
[00:00:00]
>> So numbers, why are they complex in Rust? If you're only ever used to, say, Python or TypeScript, it makes no sense why numbers are anything other than numbers, right? This is probably something you're very, very used to. 4, we would call that an integer in Rust world.
[00:00:16]
You just call that a number, right? Well, technically it's a SME. If you're not familiar with the SME, it's an optimization on a heat pointer. Anyways, if you do this, 4 divided by 3, you'd expect 1.3 forever, right? I would not expect that personally, but that's the expectation of anyone who's been in TypeScript or Python.
[00:00:33]
You'd also expect this. I don't know if that's that's okay or not. See, personally, I think that could be dangerous. But for you, you look at that and you're like, why would 4 times -1 not be -4? Well, let me tell you, is that in a Rust world or a more static type language, you have to define what your integer is and how it interacts with the world.
[00:00:54]
How binary is encoded determines what is actually happening underneath the hood. That's why you'll see effectively something like i and some number. This means an integer that can be positive or negative, a signed int. You've probably heard this phrase at some point in your lifetime. And then you can have u and some number.
[00:01:12]
That's an unsigned int. It can only be positive numbers. Typically people use unsigned ints for, say, flags. The ability to say, hey, okay, each one of these binary locations have some sort of meaning, or you use it for accessing, say, an array. Because in an array, you never would have a negative index.
[00:01:28]
That would just make no sense. No frankincense, as one person told me. And then, of course, a float. That's if you want to have a decimal precision to your binary. There's a really great, fantastic video on fast inverse square root, where they talk all about floats and how they work.
[00:01:45]
All that fun stuff, it's a great video. You will also see something like usize and isize. That just simply means that the number is the width of your architecture. So I have a 64bit system, so usize is a 64bit unsigned number, isize is a 64bit signed number. There you go.
[00:02:01]
So if I did 4 divided by 3, I'd expect the answer 1, because we're only dealing with whole numbers. So how many times can 3 go into 4? 1 time. This is not allowed. You cannot mix two different types. 4.0 divided by 3 is a float divided by an integer.
[00:02:19]
So you either need to cast your float to an integer, or your integer to a float. They have to be of the same data type. This may not be allowed if it's an unsigned number. If you have an unsigned number and you try to multiply it by -1, well, you can't do that.
[00:02:35]
It's an unsigned number, well, what are you doing with the sign in there? So there you go, this would be the error you'd get. You'd actually get an error in Rust saying you can't do that. All right, so if you've ever worked with any static language, if you've ever done Go, Java, C, C++, any of those languages, this probably seems pretty straightforward.
[00:02:54]
If you've never done it, it probably feels a little overwhelming. I'm sorry, it's just one of the hard parts of working with a language. And the other big thing that you're gonna hear me say a lot is String and stir. Now, again why are there so many types?
[00:03:08]
It makes sense once you understand it, which is that a String is a piece of data in which is allocated on a heap. Heap and stack, this might be also a foreign concept to people who are used to, say, Python or JavaScript, we'll talk more about that. A string can be mutable.
[00:03:26]
You can add stuff to it. You can't directly mutate the bits underneath, but you can add, you can compose them, you can concatenate them. Whereas a stir, you cannot do that. And that is because a stir is like a view into the String. So if you did some String in JavaScript and did substring 0 to 5, really, in the Rust world, you'd be creating a view into the String, the capital S String, you're creating a stir, a view into it.
[00:03:54]
You can't change it, but you can pass it around so people can have views into the String. You can think about this from a performance standpoint. If you have a really big String, and you take a really big subsection, you don't have to copy all that data. Instead, you can just have a pointer and the length, and now you have the same data.
[00:04:12]
And you can hand it around all you want, and no one has to make these huge copies. Or in JavaScript land, when you do substring, do you get a new string, or do you get a reference? I honestly have no idea which one you get. I'm sure there's rules that change it, depending on how big the String is.
[00:04:27]
Is the bigger String dropped? When is it dropped? There's probably a bazillion and a half rules. Even if it is dropped, but you still have a reference, it probably maybe makes a copy at that point. I have no idea, right? It's very, very complicated because you don't have control over how memory works.
[00:04:41]
You'll also see something like this every now and then, which this just simply means, I am a reference to a list of something. And so the something would be defined in here. So this would be a, I'm a reference to a list of u8s. Or that's really just what a String is.
[00:04:56]
It's just a series of 8-byte or 8-bit little data pieces there. So when I say the word String, I mean capital S String. When I say the word stir, I mean a reference to a String. We can do a little quick whiteboarding. I think that would probably be a little bit nice just to make sure.
[00:05:15]
So if you have something like this, so I'm just gonna do this for String. So this is a capital S String, even though this is not how you define it in Rust. So if I did hello world, yes, I do have beautiful handwriting. Thank you very much for noticing.
[00:05:28]
And if I did something like this, y=x[0,.5]. Visually, what that's actually gonna do is x is gonna be this. x is gonna have a pointer to somewhere on the heap that has the memory, hello world. It's gonna have a length associated with it. How much data that it's currently using, and a capacity.
[00:05:52]
The capacity is how much more data can be added before it needs to reallocate itself somewhere else. Because remember, when you're managing memory, it's not like you can just grow infinitely, cuz you may grow into the next variable. Everything's stored somewhere on your computer, you just don't often think about that.
[00:06:07]
This makes a lot of sense if you ever programmed in the C world. You kind of malloc a certain amount of memory, you can malloc more than you need. And you can kinda grow within those bounds, but then you have to re-malloc once you have exceeded your bounds.
[00:06:18]
You need the computer to tell you where you can store it, cuz maybe you can just grow your region. Maybe you can't cuz there's something nearby. And then a stir of this one, it's really just referencing hello, right? That's all it's referencing is hello. Therefore, all it really needs is a pointer and a length.
[00:06:34]
There's no capacity, right? It doesn't need to grow. It doesn't need anything about it. And we'll talk more about stack and heap and how that is, but this thing is pointing effectively to the same place as my String. We do have a question over there.
>> Is stir and u8 equal [u8]?
[00:06:52]
>> No, they're not equal. So the question is, is reference String right here, or stir reference, are the same thing as this, a slice? No, they're technically not, because a stir implies utf-8 encoding. Not all 8bit arrays are like, they're not equivalent to a String, cuz String has some encoding requirements.
[00:07:17]
So long as the encoding requirements are met, then yes, a view into an into a little u8 array is the same thing as a stir. It may not be the same thing as a stir in Rust, because you haven't defined the types, you can convert between them. I think there's either a library or a standard method to convert between them.
[00:07:34]
But they are or are not the same thing. There's a risk involved in converting.
>> If the String changes, will stir change as well?
>> So if the String changes, will stir change as well? So a thing about a String is it's not like C. So you can't just point it to offset 3 and just start changing it.
[00:07:53]
You cannot do that, and so that it's just not an allowable item. And also there's this whole borrow checker thing, which we haven't talked about. So I'll tell you this much, you can't have your String, and a pointer to your String, and change your String, that's just not allowed.
[00:08:08]
That's just not a thing you can do in Rust. We'll go over that. So that situation just can't exist. Some basics on Rust. I do wanna do a little bit more on Rust, just so you have some ideas here. When you're starting out Rust, so when you leave this class, and you go and you try to build your own CLI application, and you find yourself using unwraps or clones, it's okay, when you're starting off, it's okay to do things the wrong way, cuz you're just learning how to use the language, you're getting familiar with it.
[00:08:34]
But just know that unwraps and clones typically mean you're doing something that's either dangerous or just not very good for performance. You should ask yourself, why am I doing this? There probably is a better way to do it. But maybe at your skill level you can't quite overcome that, and that's okay.
[00:08:50]
When I first started off using Rust for advent of code, it was just clones and unwraps everywhere because I had no idea what I was doing. And then over the time of working with it, I became better and better, and I can use them less and less. And so I'm not a very strict individual, I think that learning is most fun when you learn as fast as possible using your hands and not your eyes.
[00:09:11]
So that's why I think unwraps and all this are fine in the beginning.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops