You MUST KNOW These Traits in Rust

Oliver Jumpertz
3 Mar 202418:36

Summary

TLDRこの動画スクリプトでは、Rust言語の特徴的なトレイト「From」と「Into」、およびそれらのエラーハンドリングバージョン「TryFrom」と「TryInto」について解説しています。Rustにおけるデータの所有権と借用の概念を理解し、これらのトレイトを使用してAPIの使いやすさを向上させる方法を学ぶことができます。また、データの変換が失敗する可能性がある場合にどのように扱うか、そして参照と借用に関する「AsRef」と「AsMut」トレイトの使い方についても説明されています。この知識は、Rustの標準ライブラリや一般的なクレートのAPIをより理解し、より効率的にコードを書くための重要な基盤となります。

Takeaways

  • 🌟 Rustの借用チェッカーを克服すると、コードがよりスムーズに流れるようになります。
  • 📚 Rustにおけるidiomaticなコードを学ぶことの重要性と、特定のトレイト(from, into, try_from, try_into)を知ることがAPIの使いやすさに寄与します。
  • 🔄 `from`と`into`は、Rustでの型変換の基本であり、`into`は`from`の逆演算です。
  • 📊 Rustは所有データと借用データの2つのタイプがあり、`from`と`into`はこれらのデータの変換に関連しています。
  • 🚀 `from`トレイトは、変換が失敗しないことを前提としており、計算コストが高い可能性があることを考慮する必要があります。
  • 🔧 `try_from`と`try_into`は、失敗が可能な変換を扱うために存在し、関連型`Error`を定義することができます。
  • 🛠️ 型変換を標準化することで、Rust開発者が検索しやすくなり、特定の型変換に必要なメソッドを簡単に見つけることができます。
  • 📌 関数のジェネリクスと`Into`トレイトの使用により、APIのエルゴノミクスを向上させることができます。
  • 🔄 `as_ref`と`as_mut`は、所有権を取得せずに値を借用するためのトレイトで、参照の変換がより簡単に行えます。
  • 📝 標準ライブラリは`as_ref`と`as_mut`のブランケット実装を提供しており、異なるタイプのデータの借用を自動的に扱うことができます。
  • 🔗 これらのトレイトの理解と使用は、Rustでのコードの改善と、既存のクレートやAPIの理解を深めることに役立ちます。

Q & A

  • Rustの借用チェッカーとは何ですか?

    -Rustの借用チェッカーは、所有データと借用データの管理を担当し、安全なメモリアクセスを保証するコンパイラの機能です。

  • Rustにおける所有データと借用データの違いは何ですか?

    -所有データは、コードブロックがメモリを解放する責任を持っており、借用データはそのメモリの解放を後で他のコードブロックが行うことになります。

  • FromトレイトとIntoトレイトの違いは何ですか?

    -Fromトレイトは変換の所有権を取得する変換を定義し、Intoトレイトは変換の所有権を放棄する変換を定義します。IntoはFromの逆です。

  • Rustで標準的な変換を行うにはどうすればいいですか?

    -Rustで標準的な変換を行うには、FromトレイトとIntoトレイトを実装し、それらを使用して変換を行うことが必要です。

  • TryFromとTryIntoはどのような状況で使用されるのでしょうか?

    -TryFromとTryIntoは、変換が失敗する可能性がある場合に使用されます。これらのトレイトは、エラーを返すことができます。

  • Rustのトレイトに関連する型がある場合、どのようにエラーを定義するのですか?

    -関連する型がある場合、Associated typeを使用してエラーの型を定義することができます。

  • Rustで借用参照を取得する方法は何ですか?

    -Rustで借用参照を取得するには、AsRefトレイトとAsMutトレイトを使用することができます。これらは、参照を取得するためのcheapな方法を提供します。

  • Rustでファイルの名前を変更する方法は何ですか?

    -Rustでファイルの名前を変更するには、std::fsモジュールのrename関数を使用することができます。この関数は、所有権を取得せずにパスを借用します。

  • Rustで標準ライブラリが提供するAsRefとAsMutの利点は何ですか?

    -AsRefとAsMutは、関数に借用参照を渡す際に、コードの可読性と使いやすさを向上させます。また、標準ライブラリは、これらのトレイトのblanket実装を提供し、複数の参照を自動的にdereferenceします。

  • RustでAPIの使いやすさを向上させるためにどのようなアプローチがとることができますか?

    -APIの使いやすさを向上させるために、関数をジェネリックにし、Intoトレイトを利用して、所有権を取得するデータを受け取ることができます。また、AsRefやAsMutを利用して借用参照を渡すこともできます。

Outlines

00:00

🤖 Rustのidiomaticコードとtraitsの理解

Rustは初心者には厳しい言語ですが、borrow Checkerを克服した後、コードがスムーズに流れ始めます。この段階でidiomaticなコードとtraitsを学ぶことが重要です。特に、型変換を扱うtraitsである`From`と`Into`、およびエラーを許容する`TryFrom`と`TryInto`について理解を深めましょう。これらのtraitsはAPIの使いやすさとコードの効率を劇的に向上させる効果があります。

05:01

🔄 データ型変換の標準化と利点

Rustでは所有データと借用データの概念があり、これに基づいて`From`と`Into`の2つの型変換方法があります。`From`は変換元のデータ型の所有権を取得し、`Into`は変換先のデータ型に変換します。これらのtraitsは標準化された変換方法を提供し、開発者が型変換に必要なメソッドを簡単に検索できるようになります。また、APIの改善や内部データの扱いを簡素化する効果もあります。

10:04

🚀 失敗可能な変換と`TryFrom`/`TryInto`

型変換が失敗する可能性がある場合、`TryFrom`と`TryInto`が使用されます。これらのtraitsはエラーを返すことができます。`TryFrom`は変換元の型からエラー型を指定し、`TryInto`は変換先の型が`From`を実装していることを要求します。これらのtraitsを使用することで、失敗時のエラー処理が柔軟になり、コードの信頼性が向上します。

15:05

📚 借用参照と`AsRef`/`AsMut`の使用

Rustでは所有権を必要としない場合、借用参照を扱う`AsRef`と`AsMut`のtraitsがあります。`AsRef`は借用参照を返し、`AsMut`は可変借用参照を返します。これらのtraitsを使用することで、APIの使いやすさやコードの効率が向上し、特に深い型のネストがある場合に有効です。標準ライブラリはこれらのtraitsのblanket実装を提供しており、開発者が簡単に実装できるようになっています。

Mindmap

Keywords

💡Rust

Rustは、システムプログラミング向けのプログラミング言語で、所有権と借用の概念を中心としたメモリ安全性と並行性の確保を特徴としています。このビデオでは、Rustのidiomaticなコードを学ぶことの重要性について説明されています。

💡Borrow Checker

借用チェッカーはRustコンパイラの一部で、所有権と借用のルールを強制します。これにより、安全なメモリ管理が保証され、データ競合やNULLポインタのアクセスなどの問題を防ぐことができます。

💡From and Into Traits

FromとIntoは、Rustで型変換を行うためのトレイトで、所有権を取得する型変換を定義します。Fromは、変換元の型から変換先の型に所有権を移す際に使用され、Intoはその逆の操作に使用されます。

💡Idiomatic Code

Idiomatic Codeとは、特定のプログラミング言語の慣用的なスタイルやパターンに従ったコードを指します。Rustにおいては、idiomaticなコードを書くことで、より自然で読みやすいコードを作成できます。

💡TryFrom and TryInto

TryFromとTryIntoは、FromとIntoトレイトのエラーハンドリングを可能にするRustのトレイトです。これらのトレイトを使用することで、型変換が失敗した際に、適切なエラーを返すことができます。

💡AsRef and AsMut

AsRefとAsMutは、Rustのトレイトで、参照を借用するための方法を提供します。AsRefは、非ミュータブルな参照を返し、AsMutはミュータブルな参照を返します。これにより、関数に参照を渡すことができます。

💡Generic Functions

ジェネリック関数は、複数の型に適用できる関数です。Rustでは、ジェネリックなコードを書くことで、コードの再利用性が高まり、可読性も向上します。

💡Type Conversion

型変換は、プログラミングにおいて、ある型の値を別の型に変換する操作を指します。Rustでは、型変換が所有権の移転を伴うため、特に注意が必要です。

💡Ownership

所有権は、Rustにおけるメモリ管理の核心概念です。所有権を持ち、そのデータを使用するコードブロックは、メモリの解放も責任を持っています。

💡Ergonomics

Ergonomics(人体工学)は、ユーザーの使いやすさを重視するデザインの概念です。プログラミング言語においては、APIの使いやすさを向上させる設計を指します。

💡Associated Types

関連型は、トレイト内で定義される型で、トレイトの実装時に具体的な型を指定することができます。これにより、トレイトの機能をより柔軟に利用できます。

Highlights

Rust's borrow checker makes the language challenging for beginners but rewarding once mastered.

Understanding idiomatic Rust code involves learning about traits like `From` and `Into`.

Traits `From` and `Into` are essential for type conversion in Rust.

In Rust, data can be owned or borrowed, affecting how conversion traits work.

The `From` trait is used for conversions that transfer ownership.

The `Into` trait is the reciprocal of `From` and is used when the target type implements `From` for the source type.

Using `From` and `Into` traits can improve API ergonomics and make code more idiomatic.

The `TryFrom` and `TryInto` traits handle failable conversions, allowing for error handling.

Associated types in `TryFrom` allow for specifying the error type for conversion failures.

The `as_ref` and `as_mut` traits are used for cheap reference borrowing, improving API usability.

The Rust standard library provides blanket implementations for `as_ref` and `as_mut`, simplifying type handling.

The `rename` function from the standard library demonstrates the use of `as_ref` for non-owning operations.

Borrowing mutable references with `as_mut` allows for modifying data without taking ownership.

The standard library's blanket implementations for mutable references enable passing多层 mutable references.

Understanding and using these traits can lead to more efficient and idiomatic Rust code.

Familiarity with these traits can help developers better understand and utilize crates and APIs in Rust.

The transcript provides a comprehensive overview of Rust's type conversion traits and their practical applications.

Transcripts

play00:00

rust might not be the most beginner

play00:01

friendly language but after you've

play00:03

battled and hopefully defeated the

play00:04

borrow Checker Things become way easier

play00:07

and your code slowly begins to flow more

play00:09

and more this is however also the time

play00:12

when you really need to learn more about

play00:13

rust and especially idiomatic code and

play00:17

there are a few traits that you need to

play00:18

know about because they will make your

play00:21

API so much better to use and even ease

play00:23

your own life up a lot the traits I'm

play00:25

talking about are from and into try from

play00:28

and try into and as Raven as mute these

play00:32

trades are the base of converting

play00:34

between types and rust and you should

play00:36

really be aware of and use them actively

play00:39

so let's take a look at them and find

play00:41

out how they work why you need them and

play00:44

where you can use them let's first talk

play00:46

about from and into because they are two

play00:48

sides of the same metal and into is

play00:51

actually just the reciprocal of the from

play00:53

trade but more on that later conversion

play00:56

happens all the time in software often

play00:58

we have one type of data that we need to

play01:01

convert into another type of data

play01:03

database results need to be converted

play01:05

into API responses API requests need to

play01:08

be converted to an internal

play01:10

representation or a software can work

play01:11

with and so on in Rust there are two

play01:14

types of data there is owned data and

play01:17

borrowed data and it's one of the core

play01:20

principles of rust when a code block

play01:22

owns some data it's also responsible for

play01:25

freeing the corresponding memory when it

play01:27

has finished whatever it wanted to do if

play01:29

if a code block only borrows it it just

play01:32

has to return the borrow data so to say

play01:34

and let someone else take care of

play01:36

freeing that block of memory later as

play01:39

rust has these two ways of dealing with

play01:41

data it's also no wonder that there are

play01:43

at least two ways of converting it from

play01:45

an into our trades that deal with the

play01:47

conversion of data we want to get

play01:49

ownership of which means that after the

play01:51

conversion happened ownership is passed

play01:53

from the caller whoever that might be to

play01:56

us or better our logic this means that

play01:59

we we decide when the lifetime of that

play02:01

converted data ends if we take a look at

play02:04

the implementation of the from trade we

play02:06

can quickly see what it focuses on it

play02:08

takes a generic Source type T and

play02:11

returns itself which refers to whatever

play02:13

type implements from for itself as the

play02:17

argument is not borrowed because there

play02:19

is no ENT in front of it the target type

play02:22

is moved or in other words consumed and

play02:25

thus gives ownership to from as the

play02:28

function itself only returns self it

play02:30

means that we deal with a conversion

play02:31

that can't fail from should always

play02:34

return a result so it's not suited for

play02:36

conversions that can potentially fail

play02:38

due to constraints a conversion model

play02:40

with from can or cannot be

play02:42

computationally expensive but in general

play02:44

we should assume that it is expensive

play02:47

which is important to keep in mind when

play02:49

we use it next to from there's in two

play02:52

which is the reciprocal of from and if

play02:54

we take a look at it we can see that

play02:56

into takes the type that implements it

play02:59

and returns a Target Type U which in the

play03:01

end is just another way of the

play03:02

conversion from does looking at the

play03:05

signature we can see that from implies

play03:07

into the target type is required to

play03:09

implement from for into Source type and

play03:12

the blanket implementation of into makes

play03:15

use of exactly that by only calling from

play03:17

on the target type passing self as the

play03:20

argument oh and like with from the

play03:23

argument self in this case is moved and

play03:26

thus consumed to make clear that into is

play03:28

really the reciprocal of from and to

play03:31

help you understand it let's take a look

play03:32

at how we can construct a string from an

play03:34

Str Str in Rust we can either create

play03:37

that string by calling string from

play03:39

passing an Str Str into it call from on

play03:42

the from trade but then we have to

play03:44

explicitly State our type call into on

play03:46

the Str Str and explicitly type our

play03:49

variable string or by calling into on

play03:52

the into trade also explicitly typing

play03:54

our variable all lines do exactly the

play03:57

same in the end we have a dynamic keep

play03:59

allocated string at our hands created

play04:02

from an immutable utf8 bite sequence and

play04:04

Str Str somewhere within our programs

play04:07

memory which of the ways we use is

play04:09

usually a matter of taste but we will

play04:11

mostly find versions 1 and three out in

play04:14

the wild which is either calling from on

play04:16

the target type and calling into

play04:18

directly on the value of the type we

play04:19

have at hand the standardized way of

play04:22

converting values is already pretty

play04:24

valuable on its own if we stick to it

play04:26

rust devs will know what to search for

play04:28

and won't need to go and see which

play04:31

method they might need to use to convert

play04:33

from one type to another if our type

play04:35

implements from other devs will know how

play04:38

to use it okay that was a lot of theory

play04:41

so let's see how we can effectively use

play04:43

these two traits besides standardizing

play04:45

conversions with them imagine that we

play04:48

have a simple struct that models the

play04:50

metadata of a YouTube video this struct

play04:53

has at least two properties a title and

play04:55

a description both of typ string if we

play04:59

now want to create a factory function

play05:00

for that struct we could just let our

play05:03

users pass two strings to it it's

play05:05

already clear that we want to take

play05:07

ownership of that data because well

play05:10

whatever we put inside the struct needs

play05:12

to live as long as the struct itself

play05:14

does but this API doesn't have a lot of

play05:17

ergonomics if we want to construct an

play05:19

instance of that struct it only accepts

play05:21

two strings and that's it we can always

play05:24

let the users of our API convert their

play05:26

types themselves like sdrs for example

play05:29

but that leaves some pretty ugly code

play05:31

behind for them if we change the

play05:33

signature of our Factory method to

play05:35

accepting it into string however the

play05:37

ergonomics of our Factory suddenly

play05:39

become way better our Factory is now

play05:42

generic over a type that must Implement

play05:44

into string and it doesn't matter which

play05:46

type that is now the call with an S strr

play05:49

simply looks like this which is way

play05:51

better for users of such an API because

play05:53

they don't have to explicitly convert

play05:54

between types anymore they can Implement

play05:57

into string for their types if they wish

play05:59

to

play06:00

and then pass them to our function we

play06:02

can extend this example to anything else

play06:05

but in general whenever we want to

play06:07

accept data that we need to take

play06:08

ownership of we should at least consider

play06:11

making our function generic and

play06:13

accepting an in of whatever type we need

play06:15

because it can improve the ergonomics of

play06:17

our API doing so also makes sense for

play06:20

internal types because it allows us to

play06:22

implement from for some of them exactly

play06:24

once for each type we need get the into

play06:27

implementation for free and save

play06:28

ourselves lot of work when we pass data

play06:31

of different types around within the

play06:33

internals of our software until now we

play06:35

have only talked and learned about

play06:37

conversions that cannot fail but what if

play06:40

they can what if they are failable the

play06:43

signature from and into doesn't allow

play06:45

for any errors and panics should

play06:48

generally be avoided because no one

play06:50

likes software that just shuts down

play06:52

whenever it hits a small inconvenience

play06:54

and this is why Try from and try into

play06:57

exist if we take a look at try from from

play06:59

source code we can see that it looks a

play07:01

little more complicated than from but it

play07:04

actually only has one more advanced

play07:06

feature inside it a so-called Associated

play07:09

type arror try from is generic over type

play07:12

T which means that t is the source and

play07:15

self is the target type that we

play07:17

Implement try from for this however

play07:19

leaves one problem how can we make the

play07:22

error generic it's not as easy as simply

play07:24

adding another generic type parameter

play07:27

which is why the associated type exists

play07:30

this Associated type is just a simple

play07:31

placeholder that we can specify when

play07:34

implementing the trade which allows us

play07:36

to specify the type of error we want to

play07:39

return in case the conversion fails

play07:42

before we look at an example though we

play07:43

can pay a short wizard to try into

play07:45

source code and identify that like into

play07:48

for from try into also has a blanket

play07:51

implementation which only requires us to

play07:53

implement Tri from and get try into for

play07:56

free everything within try into is

play07:58

direct linked to Tri from even its

play08:01

Associated type is bound to the one

play08:03

within Tri from so there's really no

play08:05

work for us to do unless we have to in

play08:09

really rare circumstances with that done

play08:12

let's now look at an example scenario

play08:14

HTTP and https both work over TCP they

play08:18

are mainly the foundation of the

play08:20

internet as it is today with https being

play08:22

the preferred standard for public

play08:24

traffic if we were to implement an HTTP

play08:27

and https server we would have to think

play08:30

in bite streams that our application

play08:32

receives and correctly interpret those

play08:34

bites at the beginning there is a new

play08:36

connection which any client opens to our

play08:39

server on its first request that's the

play08:41

moment we have to determine whether we

play08:42

are dealing with HTTP or https traffic

play08:46

and a way to distinguish one from the

play08:47

other is by looking at exactly the first

play08:50

bite of the first TCP packet in case of

play08:53

https that bite will always be 22

play08:56

because of the TLs handshake that occurs

play08:57

in the beginning if if the connection is

play09:00

only through HTTP we receive any bite

play09:02

between 32 and 127 inclusive a way to

play09:06

model this is to use an enum with

play09:08

exactly two members one that signals

play09:11

that the type of the connection is HTTP

play09:13

and the other that it's https this e

play09:16

alone doesn't help us though we deal

play09:18

with a bite stream which is just a

play09:20

buffer of btes that are u8 and rust case

play09:22

and this already screams for some form

play09:24

of conversion although we are already

play09:27

talking about the TR versions of from it

play09:28

into

play09:29

it's still good to understand why

play09:31

they're necessary in this case you

play09:33

probably still remember that we have a

play09:35

very limited set of acceptable values

play09:36

for our Ena to be precise we only accept

play09:40

96 possible values of a u8 that can take

play09:43

any number from 0 to 255 inclusive this

play09:46

leaves many bites that don't fit into

play09:48

our enom and what do we do if we cannot

play09:51

deal with certain values correct we

play09:54

return an arrow if we receive one we

play09:56

can't work with we can model exactly

play09:58

that by by implementing triy from u8 for

play10:00

our enum traffic type as our Arrow we

play10:03

use one that we Define ourselves with

play10:05

friendly help from this arrow and within

play10:08

the function we use a match statement

play10:10

that checks the value we convert from

play10:12

for all possible States if the bite we

play10:14

receive is 22 we deal with https traffic

play10:18

if the bite we receive is in the range

play10:20

between 32 and 127 inclusive we deal

play10:24

with HTTP traffic and if we receive

play10:27

anything else we return on an err with

play10:29

our self-made P error which signals that

play10:32

we got an invalid first bite with this

play10:35

implementation we've created a way to

play10:37

convert the first bite of a TCP stream

play10:39

into an enum that tells us what type of

play10:41

connection we deal with and with that we

play10:44

can subsequently Implement logic to deal

play10:46

with each individual type this is of

play10:49

course not the end of it we can also use

play10:51

try from and try into as a function

play10:54

argument the same way we already did

play10:56

with from and into if we want wanted to

play10:59

create the Boolean predicate function to

play11:00

tell us whether we deal with HTP or

play11:03

https or none of them at all we can do

play11:06

it by accepting a try into traffic types

play11:09

or parameter and then base our Logic on

play11:12

the result of the conversion admittedly

play11:14

the use cases for Tryin as an argument

play11:16

are fewer than those for into but

play11:19

especially in create internal code you

play11:21

can make good use of it so it's still a

play11:23

very valid use case up to now we've only

play11:26

talked about conversions that take

play11:28

ownership but more often than not we

play11:30

don't need any ownership to do what we

play11:32

want to do in fact we can even argue

play11:35

that the majority of the time borrowing

play11:37

a value is more than enough this however

play11:40

rules out using from into try from and

play11:43

try into for cases like this sref exists

play11:47

and we can take a quick look at its

play11:49

source code and try to make a little

play11:51

sense of it srf is a generic trade with

play11:54

exactly one function to implement as ref

play11:57

as ref borrows itself so it doesn't move

play12:00

itself like the other conversions do and

play12:02

it returns a reference to a Target type

play12:04

T in the end s ref is meant for cheap

play12:07

conversions of references if a type A

play12:09

contains a type B implementing as ref B

play12:12

for type A allows us to return the

play12:15

nested reference of B with an a which is

play12:17

very cheap to do and further it also

play12:20

saves users of our apis to pass huge

play12:22

call chains into our functions like from

play12:25

into and the others do but let's as an

play12:28

example look at how we can work with

play12:30

files in Rust to make it even more

play12:32

precise let's imagine that we are

play12:34

dealing with renaming files which is a

play12:36

common operation whenever we download a

play12:38

file our browsers tend to create a

play12:40

temporary file until the download is

play12:42

finished and rename it to its real name

play12:44

after this if we want to do the same in

play12:47

Rust we can use a sweet little helper

play12:49

method from the standard Library within

play12:50

the fs module called rename it accepts

play12:54

two paths the source and the Target and

play12:57

when it has finished its execution the

play12:59

source file has the name of the target

play13:00

we supplied this function doesn't

play13:02

actually need ownership of the arguments

play13:04

it only needs the paths to identify the

play13:07

source file and to get a name and an

play13:09

absolute path to the Target file so

play13:12

borrowing makes perfect sense even more

play13:15

interestingly it accepts more than only

play13:17

paths we can even mix and match

play13:19

arguments as we like rename still works

play13:22

and still only borrows its arguments if

play13:25

we take a look at rename source code we

play13:27

can spot how the magic works it makes

play13:30

use of as ref and requires both of its

play13:32

parameters to implement as ref path

play13:34

that's it the actual magic however is

play13:37

nested within the individual

play13:38

implementations of his ref for multiple

play13:40

types within the standard Library there

play13:42

are quite a few types that Implement as

play13:44

ref path which is why you can call

play13:46

rename with many different types of data

play13:49

the cheap conversion from whatever type

play13:52

to a path reference happens under the

play13:54

hood actually even within paths Factory

play13:56

function which converts any type it

play13:59

receives to a reference of an OS string

play14:01

to create a path from let's however look

play14:04

at another example to get an even better

play14:07

idea of how SRA is intended to work and

play14:10

how we can make use of it let's imagine

play14:12

we build a block system with various

play14:14

data the most basic form of the data we

play14:17

need is a post that has a few crucial

play14:20

properties there are also Advanced types

play14:22

of post like video guides that we need

play14:24

to model as rars however lack

play14:26

inheritance for good reason we usually

play14:28

model it with the new type principle and

play14:31

create a new type adding the additional

play14:33

properties we need and nesting the

play14:36

original type within it now we want the

play14:38

function to notify all of our regular

play14:40

readers that a new post has been

play14:42

published it needs some metadata from

play14:45

the post to create an email with which

play14:47

is why borrowing is enough and then does

play14:49

some magical work to notify all readers

play14:51

of the new content passing the

play14:53

references is perfectly fine and fast

play14:56

but the deeper post is nested with an

play14:58

Advanced types the longer the call

play15:00

chains become calling the post property

play15:03

on the video guide is fine but it's

play15:05

already looking a little ugly this is

play15:07

where we can bring s ref in and

play15:09

Implement s ref post for all of our

play15:11

types then we can change the signature

play15:14

of our notify function to accept any

play15:16

type that implements as ref post which

play15:19

then allows us to get a cheap reference

play15:21

to a post no matter how deeply it is

play15:23

nested within a random time this also

play15:25

beautifies the Coster of function

play15:27

because we can now just pass any type

play15:29

that implements as Rift post but wait a

play15:32

second have you noticed something if not

play15:37

don't worry let's take a closer look

play15:39

notify does magically work by passing a

play15:41

reference to a post in a video guide

play15:43

although we have only implemented as ref

play15:45

post for post and video guide and not

play15:48

for reference post and reference video

play15:50

guide that's actually another blanket

play15:52

implementation within the standard

play15:53

Library doing some magic for us this

play15:56

blanket implementation automatically

play15:58

gifts us with an implementation of srf

play16:00

post for both reference post and

play16:02

reference video guide as soon as we

play16:05

implement it for the non-reference types

play16:07

oh and even better the standard Library

play16:10

even goes one step further and

play16:12

implements s ref t for us for any

play16:15

mutable reference which means that we

play16:17

can also automatically pass mutable

play16:19

references to any function that expects

play16:21

an srf T without any compiler errors

play16:24

that's quite some time saved and it

play16:26

improves the usability of our API I even

play16:29

more because now users don't even have

play16:31

to think about what they need to pass

play16:34

they can pass us what they have at hand

play16:37

there is one last thing missing however

play16:39

borrowing a mutable reference that's

play16:41

something as ref can't cover which is

play16:44

why as mute exists a look at its source

play16:46

code reveals that it's mainly the same

play16:48

as as ref with the only difference being

play16:51

that it requires a mutable self and

play16:53

returns a mutable reference together

play16:55

with a different function name this

play16:57

makes us mute the way to go if we don't

play17:00

want an immutable but a mutable borrow

play17:02

somewhere with no API its function name

play17:05

is different from as ref which allows us

play17:07

to implement both traits and this then

play17:10

allows us to make explicit calls that

play17:12

also Mark Our intention s ref if we want

play17:15

an immutable reference and S mute if we

play17:18

want a mutable one using the same block

play17:21

example we already used for S ref we

play17:23

could also implement the function that

play17:24

can mutate our post to store the date we

play17:27

notified our users from example this is

play17:29

nearly the same as RS ref example just

play17:32

that we can work with mutable references

play17:34

this time oh and who would have thought

play17:37

the standard Library once again gives us

play17:38

a blanket implementation for mutable

play17:40

references which AO dereferences

play17:42

multiple layers of mutable references

play17:44

for us or in other words even a mutable

play17:47

reference of a mutable reference of a

play17:49

type T can be passed as an S mute T and

play17:53

is automatically dereferenced once again

play17:56

something that saves us time and makes

play17:58

apis more usable so overall a win-win

play18:02

situation pH that was a lot to grasp

play18:06

take some time to process that first and

play18:08

after that you will hopefully realize

play18:10

how much better your code becomes if you

play18:12

begin to consequently use these trades

play18:14

in your daily work or your side project

play18:16

and even if you don't have the time or

play18:18

opportunities to use them yourselves you

play18:21

will still profit from that knowledge

play18:22

because you now probably understand a

play18:24

few crates and their apis and especially

play18:27

the standard Library better than you did

play18:28

before so hey enjoy your newly gained

play18:32

knowledge and until then see you in the

play18:34

next video

Rate This

5.0 / 5 (0 votes)

Related Tags
RustプログラミングトレイトFromIntoTryFromTryIntoデータ変換エラー処理API設計コード改善
Do you need a summary in English?