final state of first presentation
Getty Ritter
10 years ago
| 1 | 1 | % The Rust Programming Language |
| 2 | 2 | % G.D. Ritter |
| 3 |
% |
|
| 3 | % June 2015 | |
| 4 | 4 | |
| 5 | 5 | # The Rust Programming Language |
| 6 | 6 | |
| 41 | 41 | |
| 42 | 42 | ## Example Program |
| 43 | 43 | |
| 44 | ~~~~{.haskell} | |
| 45 | data Point = { x, y : Int } | |
| 46 | ||
| 47 | addPoint : Point -> Point -> Point | |
| 48 | addPoint l r = { x = l.x + r.x, y = l.y + r.y } | |
| 49 | ||
| 50 | main : () | |
| 51 | main = { let a = { x = 1, y = 2 } | |
| 52 | ; let b = malloc { x = 4, y = 3} | |
| 53 | ; print (addPoint a (deref b)) | |
| 54 | ; free(b) | |
| 55 | } | |
| 56 | ~~~~ | |
| 44 | A program that: | |
| 45 | ||
| 46 | - Defines a `point` struct. | |
| 47 | - Gives that `point` struct two machine integers as | |
| 48 | fields. | |
| 49 | - Defines an `add` function that takes and returns | |
| 50 | two `point`s _by value_. | |
| 51 | - Has a `main` function that: | |
| 52 | - Creates a `point` on the stack | |
| 53 | - Creates a `point` on the heap | |
| 54 | - Adds the two (after dereferencing the second) | |
| 55 | - Prints the result | |
| 56 | - Frees the second point | |
| 57 | 57 | |
| 58 | 58 | # Systems Programming Languages |
| 59 | 59 | |
| 166 | 166 | ## Rust |
| 167 | 167 | |
| 168 | 168 | ~~~~{.rust} |
| 169 | #[derive(Debug,Clone,Copy)] | |
| 169 | 170 | struct Point { x: isize, y: isize } |
| 170 | 171 | |
| 171 | impl Point { | |
| 172 | fn add(self, other: Point) -> Point { | |
| 173 | Point { x: self.x + other.x, | |
| 174 | y: self.y + other.y } | |
| 175 | } | |
| 172 | fn add(l: Point, r: Point) -> Point { | |
| 173 | Point { x: l.x + r.x, y: l.y + r.y } | |
| 176 | 174 | } |
| 177 | 175 | |
| 178 | 176 | fn main() { |
| 179 | 177 | let a = Point { x: 1, y: 2 }; |
| 180 | 178 | let b = Box::new(Point { x: 4, y: 3 }); |
| 181 | println!("{:?}", a.add(*b)); | |
| 182 | } | |
| 183 | ~~~~ | |
| 184 | ||
| 185 | # What Makes Rust Interesting | |
| 186 | ||
| 187 | > It's like C++ grew up, went to grad school, started dating Haskell, and | |
| 188 | > is sharing an office with Erlang... | |
| 189 | > | |
| 190 | > —Michael Sullivan | |
| 179 | println!("{:?}", add(a, *b)); | |
| 180 | } | |
| 181 | ~~~~ | |
| 191 | 182 | |
| 192 | 183 | # What Makes Rust Interesting |
| 193 | 184 | |
| 197 | 188 | \includegraphics[width=.9\textwidth]{imgs/dawkins-owned.png} |
| 198 | 189 | \end{center} |
| 199 | 190 | |
| 200 | ## Ownership | |
| 201 | ||
| 202 | ~~~~{.rust} | |
| 203 | #[derive(Debug)] | |
| 204 | struct MyNum { num: i32 } | |
| 205 | ||
| 206 | fn main() { | |
| 207 | let x = MyNum { num: 2 }; | |
| 208 | println!("x = {:?}", x); | |
| 209 | } | |
| 210 | ~~~~ | |
| 211 | ||
| 212 |
# |
|
| 191 | # Preliminary Zero | |
| 192 | ## Mutability | |
| 193 | ||
| 194 | ~~~~{.rust} | |
| 195 | fn factorial(n: usize) -> usize { | |
| 196 | let result = 1; | |
| 197 | while n > 0 { | |
| 198 | result *= n; | |
| 199 | n -= 1; | |
| 200 | } | |
| 201 | result | |
| 202 | } | |
| 203 | ~~~~ | |
| 204 | ||
| 205 | # Preliminary Zero | |
| 206 | ## Mutability is NOT THE DEFAULT | |
| 207 | ||
| 208 | ~~~~{.rust} | |
| 209 | fn factorial(n: usize) -> usize { | |
| 210 | let result = 1; | |
| 211 | while n > 0 { | |
| 212 | result *= n; /* ERROR */ | |
| 213 | n -= 1; /* ERROR */ | |
| 214 | } | |
| 215 | result | |
| 216 | } | |
| 217 | ~~~~ | |
| 218 | ||
| 219 | # Preliminary Zero | |
| 220 | ## Mutability is Opt-In | |
| 221 | ||
| 222 | ~~~~{.rust} | |
| 223 | fn factorial(mut n: usize) -> usize { | |
| 224 | let mut result = 1; | |
| 225 | while n > 0 { | |
| 226 | result *= n; | |
| 227 | n -= 1; | |
| 228 | } | |
| 229 | result | |
| 230 | } | |
| 231 | ~~~~ | |
| 232 | ||
| 233 | # Preliminary One | |
| 234 | ## Polymorphism (although not on this slide) | |
| 235 | ||
| 236 | ~~~~{.rust} | |
| 237 | fn i32_id(a: i32) -> i32 { | |
| 238 | a | |
| 239 | } | |
| 240 | ||
| 241 | fn make_i32_pair(left: i32, right: i32) -> (i32, i32) { | |
| 242 | (left, right) | |
| 243 | } | |
| 244 | ~~~~ | |
| 245 | ||
| 246 | # Preliminary One | |
| 247 | ## Polymorphism (this slide is, like, _totally_ polymorphic) | |
| 248 | ||
| 249 | ~~~~{.rust} | |
| 250 | fn id<T>(a: T) -> T { | |
| 251 | a | |
| 252 | } | |
| 253 | ||
| 254 | fn make_pair<A, B>(left: A, right: B) -> (A, B) { | |
| 255 | (left, right) | |
| 256 | } | |
| 257 | ~~~~ | |
| 258 | ||
| 259 | # Preliminary Two | |
| 213 | 260 | ## Traits |
| 214 | 261 | |
| 215 | 262 | ~~~~{.rust} |
| 216 | trait ToString { | |
| 217 | fn to_string(&self) -> String; | |
| 218 | } | |
| 219 | ||
| 220 | impl ToString for () { | |
| 221 | fn to_string(&self) -> String { | |
| 222 | "unit".to_owned() | |
| 223 | } | |
| 224 | } | |
| 225 | ~~~~ | |
| 226 | ||
| 227 | # Brief Aside | |
| 263 | struct MyNum { num: i32 } | |
| 264 | ||
| 265 | trait Sayable { | |
| 266 | fn say(&self); | |
| 267 | } | |
| 268 | ||
| 269 | impl Sayable for MyNum { | |
| 270 | fn say(&self) { | |
| 271 | println!(".oO( MyNum {{ num: {:?} }} )", self.num); | |
| 272 | } | |
| 273 | } | |
| 274 | ~~~~ | |
| 275 | ||
| 276 | # Preliminary Two | |
| 228 | 277 | ## Traits |
| 229 | 278 | |
| 230 | 279 | ~~~~{.rust} |
| 231 | fn print_excitedly<T: ToString>(t: T) { | |
| 232 | println!("{}!!!", t.to_string()); | |
| 233 | } | |
| 234 | ||
| 235 | fn main() { | |
| 236 | print_excitedly( () ); | |
| 237 | } | |
| 238 | ~~~~ | |
| 239 | ||
| 240 | # Brief Aside from the Brief Aside | |
| 241 | ## Polymorphism | |
| 242 | ||
| 243 | ~~~~{.rust} | |
| 244 | fn make_pair<A, B>(a: A, b: B) -> (A, B) { | |
| 245 | (a, b) | |
| 246 | } | |
| 247 | ||
| 248 | fn not_eq<A: Eq>(left: A, right: A) -> bool { | |
| 249 | left != right | |
| 250 | } | |
| 251 | ~~~~ | |
| 252 | ||
| 253 | # Brief Aside from the Brief Aside | |
| 254 | ## Polymorphism | |
| 255 | ||
| 256 | ~~~~{.rust} | |
| 257 |
fn |
|
| 280 | fn main() { | |
| 281 | (MyNum { num: 3 }).say(); | |
| 282 | } | |
| 283 | ~~~~ | |
| 284 | ||
| 285 | ## Output | |
| 286 | ~~~~ | |
| 287 | .oO( MyNum { num: 3 } ) | |
| 288 | ~~~~ | |
| 289 | ||
| 290 | # Preliminary Three | |
| 291 | ## Traits _and_ Polymorphism | |
| 292 | ||
| 293 | ~~~~{.rust} | |
| 294 | fn say_twice<T: Sayable>(t: T) { | |
| 295 | t.say(); t.say(); | |
| 296 | } | |
| 297 | ||
| 298 | fn main() { | |
| 299 | say_twice(MyNum { num: 7 }); | |
| 300 | } | |
| 301 | ~~~~ | |
| 302 | ||
| 303 | ## Output | |
| 304 | ~~~~ | |
| 305 | .oO( NyNum { num: 7 } ) | |
| 306 | .oO( NyNum { num: 7 } ) | |
| 307 | ~~~~ | |
| 308 | ||
| 309 | # Preliminary Three | |
| 310 | ## Traits _and_ Polymorphism | |
| 311 | ||
| 312 | ~~~~{.rust} | |
| 313 | fn print_eq<A: Eq + Sayable>(left: A, right: A) { | |
| 258 | 314 | if left == right { |
| 259 | println!("{} and {} are equal", | |
| 260 | left.to_string(), | |
| 261 |
|
|
| 315 | println!("these are equal:"); | |
| 316 | left.say(); | |
| 317 | right.say(); | |
| 262 | 318 | } else { |
| 263 | println!("{} and {} are different", | |
| 264 | left.to_string(), | |
| 265 | right.to_string()); | |
| 266 | } | |
| 267 | } | |
| 268 | ~~~~ | |
| 269 | ||
| 270 | # Brief Aside | |
| 271 | ## Traits | |
| 272 | ||
| 273 | ~~~~{.rust} | |
| 274 | /* this is /slightly/ different in the stdlib */ | |
| 275 | trait PartialEq<Rhs> { | |
| 276 | fn eq(&self, other: &Rhs) -> bool; | |
| 277 |
|
|
| 319 | println!("these are not equal:"); | |
| 320 | left.say(); | |
| 321 | right.say(); | |
| 322 | } | |
| 323 | } | |
| 324 | ~~~~ | |
| 325 | ||
| 326 | # Preliminary Four | |
| 327 | ## Built-In Traits | |
| 328 | ||
| 329 | ~~~~{.rust} | |
| 330 | /* slightly simplified from the real definition */ | |
| 331 | trait PartialEq { | |
| 332 | fn eq(&self, other: &Self) -> bool; | |
| 333 | fn ne(&self, other: &Self) -> bool; | |
| 278 | 334 | } |
| 279 | 335 | |
| 280 | 336 | /* no more methods, but more laws */ |
| 281 | trait Eq: PartialEq<Self> { } | |
| 282 | ~~~~ | |
| 283 | ||
| 284 | # Brief Aside | |
| 285 | ## Traits | |
| 286 | ||
| 287 | ~~~~{.rust} | |
| 288 | struct MyNum { num: i32 } | |
| 289 | ||
| 290 | impl PartialEq<MyNum> for MyNum { | |
| 337 | trait Eq: PartialEq { } | |
| 338 | ~~~~ | |
| 339 | ||
| 340 | # Preliminary Four | |
| 341 | ## Implementing Built-In Traits | |
| 342 | ||
| 343 | ~~~~{.rust} | |
| 344 | struct MyNum { num: i32 } | |
| 345 | ||
| 346 | impl PartialEq for MyNum { | |
| 291 | 347 | fn eq(&self, other: &MyNum) -> bool { |
| 292 | 348 | self.num == other.num |
| 293 | 349 | } |
| 296 | 352 | impl Eq for MyNum { } |
| 297 | 353 | ~~~~ |
| 298 | 354 | |
| 299 | # Brief Aside | |
| 300 | ## Traits | |
| 355 | # Preliminary Four | |
| 356 | ## Implementing Built-In Traits Automatically | |
| 301 | 357 | |
| 302 | 358 | ~~~~{.rust} |
| 303 | 359 | /* or just this */ |
| 305 | 361 | struct MyNum { num: i32 } |
| 306 | 362 | ~~~~ |
| 307 | 363 | |
| 308 | # What Makes Rust Interesting | |
| 309 | ||
| 364 | # Preliminary Four | |
| 365 | ## Format-String-Related Traits | |
| 366 | ||
| 367 | ~~~~{.rust} | |
| 368 | /* in the stdlib: */ | |
| 369 | trait Debug { | |
| 370 | fn fmt(&self, &mut Formatter) -> Result; | |
| 371 | } | |
| 372 | ||
| 373 | /* so, on on our type: */ | |
| 374 | #[derive(Debug)] | |
| 375 | struct MyNum { num: i32 } | |
| 376 | ~~~~ | |
| 377 | ||
| 378 | # What Makes Rust Interesting | |
| 310 | 379 | ## Ownership |
| 311 | 380 | |
| 312 | 381 | ~~~~{.rust} |
| 315 | 384 | |
| 316 | 385 | fn main() { |
| 317 | 386 | let x = MyNum { num: 2 }; |
| 387 | ||
| 388 | println!("x = {:?}", x); | |
| 389 | /* prints "x = MyNum { num: 2 }" */ | |
| 390 | } | |
| 391 | ~~~~ | |
| 392 | ||
| 393 | # What Makes Rust Interesting | |
| 394 | ||
| 395 | ## Ownership | |
| 396 | ||
| 397 | ~~~~{.rust} | |
| 398 | #[derive(Debug)] | |
| 399 | struct MyNum { num: i32 } | |
| 400 | ||
| 401 | fn main() { | |
| 402 | let x = MyNum { num: 2 }; | |
| 318 | 403 | let y = x; |
| 319 | 404 | println!("x = {:?}", x); |
| 320 | ||
| 405 | /* doesn't compile */ | |
| 321 | 406 | } |
| 322 | 407 | ~~~~ |
| 323 | 408 | |
| 349 | 434 | let x = MyNum { num: 2 }; |
| 350 | 435 | let y = x; |
| 351 | 436 | println!("x = {:?}", x); |
| 352 |
/* so |
|
| 437 | /* so it does not live until the print */ | |
| 353 | 438 | } |
| 354 | 439 | ~~~~ |
| 355 | 440 | |
| 363 | 448 | |
| 364 | 449 | fn main() { |
| 365 | 450 | let x = MyNum { num: 2 }; |
| 366 | let y = x.clone(); | |
| 367 | println!("x = {:?}", x); | |
| 368 |
|
|
| 451 | let y = x.clone(); /* explicit clone */ | |
| 452 | println!("x = {:?}", x); | |
| 453 | /* but this works! */ | |
| 369 | 454 | } |
| 370 | 455 | ~~~~ |
| 371 | 456 | |
| 379 | 464 | |
| 380 | 465 | fn main() { |
| 381 | 466 | let x = MyNum { num: 2 }; |
| 382 |
let y = x; |
|
| 467 | let y = x; /* implicit copy */ | |
| 383 | 468 | println!("x = {:?}", x); |
| 384 | 469 | /* as does this! */ |
| 385 | 470 | } |
| 403 | 488 | let x = MyNum { num: 2 }; |
| 404 | 489 | println!("x = {:?}", x); |
| 405 | 490 | } |
| 491 | ~~~~ | |
| 492 | ||
| 493 | # What Makes Rust Interesting | |
| 494 | ||
| 495 | ## Ownership --- Destructors | |
| 496 | ||
| 497 | ~~~~{.rust} | |
| 498 | fn main() { | |
| 499 | let x = MyNum { num: 2 }; | |
| 500 | println!("x = {:?}", x); | |
| 501 | } | |
| 502 | ~~~~ | |
| 503 | ||
| 504 | ## Output | |
| 505 | ||
| 506 | ~~~~ | |
| 507 | x = MyNum { num: 2 } | |
| 508 | dropping: MyNum { num: 2 } | |
| 406 | 509 | ~~~~ |
| 407 | 510 | |
| 408 | 511 | # What Makes Rust Interesting |
| 423 | 526 | fn main() { |
| 424 | 527 | let x = MyNum { num: 2 }; |
| 425 | 528 | let y = x.clone(); |
| 426 |
println!("x = {:?}", |
|
| 529 | println!("x = {:?}", x); | |
| 530 | } | |
| 531 | ~~~~ | |
| 532 | ||
| 533 | ## Ownership --- Special Clones | |
| 534 | ||
| 535 | ~~~~{.rust} | |
| 536 | fn main() { | |
| 537 | let x = MyNum { num: 2 }; | |
| 538 | let y = x.clone() | |
| 539 | println!("x = {:?}", x); | |
| 540 | } | |
| 541 | ~~~~ | |
| 542 | ||
| 543 | ## Output | |
| 544 | ||
| 545 | ~~~~ | |
| 546 | Cloning a MyNum... | |
| 547 | x = MyNum { num: 2 } | |
| 548 | ~~~~ | |
| 549 | ||
| 550 | # What Makes Rust Interesting | |
| 551 | ## Owned Pointers --- "Boxes" | |
| 552 | ||
| 553 | ~~~~{.rust} | |
| 554 | fn main() { | |
| 555 | ||
| 556 | let x = Box::new(5); | |
| 557 | ||
| 558 | println!("x + 1 = {:?}", *x + 1); | |
| 559 | ||
| 560 | ||
| 561 | } | |
| 562 | ~~~~ | |
| 563 | ||
| 564 | # What Makes Rust Interesting | |
| 565 | ## Owned Pointers --- "Boxes" | |
| 566 | ||
| 567 | ~~~~{.rust} | |
| 568 | fn main() { | |
| 569 | /* this acts like a `malloc` */ | |
| 570 | let x = Box::new(5); | |
| 571 | /* this dereferences the pointer */ | |
| 572 | println!("x + 1 = {:?}", *x + 1); | |
| 573 | /* as soon as ownership passes out | |
| 574 | * of scope, the box is freed */ | |
| 427 | 575 | } |
| 428 | 576 | ~~~~ |
| 429 | 577 | |
| 520 | 668 | ## References |
| 521 | 669 | |
| 522 | 670 | ~~~~{.rust} |
| 523 |
#[derive(Debug |
|
| 671 | #[derive(Debug)] | |
| 524 | 672 | struct MyNum { num: i32 } |
| 525 | 673 | |
| 526 | 674 | fn some_func(_: &MyNum) { |
| 534 | 682 | /* works! */ |
| 535 | 683 | } |
| 536 | 684 | ~~~~ |
| 685 | ||
| 686 | # What Makes Rust Interesting | |
| 687 | ||
| 688 | ## Dangling References...? | |
| 689 | ||
| 690 | ~~~~{.rust} | |
| 691 | fn main() { | |
| 692 | let mut my_ref: &i32 = &5; | |
| 693 | { | |
| 694 | let x = 7; | |
| 695 | my_ref = &x; | |
| 696 | } | |
| 697 | println!("{:?}", my_ref); | |
| 698 | } | |
| 699 | ~~~~ | |
| 700 | ||
| 701 | # What Makes Rust Interesting | |
| 702 | ||
| 703 | ## Dangling References... are statically prevented | |
| 704 | ||
| 705 | ~~~~{.rust} | |
| 706 | fn main() { | |
| 707 | let mut my_ref: &i32 = &5; | |
| 708 | { | |
| 709 | let x = 7; | |
| 710 | my_ref = &x; /* ERROR: does not live long enough */ | |
| 711 | } | |
| 712 | println!("{:?}", my_ref); | |
| 713 | } | |
| 714 | ~~~~ | |
| 715 | ||
| 716 | ||
| 717 | # What Makes Rust Interesting | |
| 718 | ||
| 719 | ## "The Borrow Checker" | |
| 720 | ||
| 721 | ~~~~{.rust} | |
| 722 | fn main() { | |
| 723 | let mut my_vec = vec![]; | |
| 724 | { | |
| 725 | let x = 7; | |
| 726 | my_vec.push(&x); /* also a problem */ | |
| 727 | } | |
| 728 | println!("{:?}", my_vec); | |
| 729 | } | |
| 730 | ~~~~ | |
| 731 | ||
| 732 | # What Makes Rust Interesting | |
| 733 | ||
| 734 | ## Lifetime Quandary | |
| 735 | ||
| 736 | ~~~~{.rust} | |
| 737 | fn keep_left<T>(left: &T, right: &T) -> &T { | |
| 738 | left | |
| 739 | } | |
| 740 | ~~~~ | |
| 741 | ||
| 742 | # What Makes Rust Interesting | |
| 743 | ||
| 744 | ## Lifetime Quandary | |
| 745 | ||
| 746 | ~~~~{.rust} | |
| 747 | fn keep_left<'l, 'r, T>(left: &l T, | |
| 748 | right: &r T) -> &l T { | |
| 749 | left | |
| 750 | } | |
| 751 | ~~~~ | |
| 752 | ||
| 753 | # A Slightly Longer Example | |
| 754 | ||
| 755 | ## A Linked List | |
| 756 | ||
| 757 | ~~~~{.rust} | |
| 758 | #[derive(Debug)] | |
| 759 | enum List<T> { | |
| 760 | Cons(T, Box<List<T>>), | |
| 761 | Nil, | |
| 762 | } | |
| 763 | ||
| 764 | fn cons<T>(car: T, cdr: List<T>) -> List<T> { | |
| 765 | List::Cons(car, Box::new(cdr)) | |
| 766 | } | |
| 767 | ||
| 768 | fn nil<T>() -> List<T> { | |
| 769 | List::Nil | |
| 770 | } | |
| 771 | ~~~~ | |
| 772 | ||
| 773 | # A Slightly Longer Example | |
| 774 | ||
| 775 | ## A Linked List | |
| 776 | ||
| 777 | ~~~~{.rust} | |
| 778 | fn head<T>(list: &List<T>) -> Option<&T> { | |
| 779 | match *list { | |
| 780 | Nil => None, | |
| 781 | Cons(ref x, _) => Some(&x), | |
| 782 | } | |
| 783 | } | |
| 784 | ~~~~ | |
| 785 | ||
| 786 | # A Slightly Longer Example | |
| 787 | ||
| 788 | ## A Linked List Lifetime | |
| 789 | ||
| 790 | ~~~~{.rust} | |
| 791 | fn main() { | |
| 792 | let mut h = None; | |
| 793 | { | |
| 794 | let lst = cons("this", | |
| 795 | cons("that", | |
| 796 | cons("the other", | |
| 797 | nil()))); | |
| 798 | h = head(lst); | |
| 799 | } | |
| 800 | println!("{:?}", h); | |
| 801 | } | |
| 802 | ~~~~ | |
| 803 | ||
| 804 | ||
| 805 | # A Slightly Longer Example | |
| 806 | ||
| 807 | ## Linked List: A Lifetime Original Picture | |
| 808 | ||
| 809 | ~~~~{.rust} | |
| 810 | fn head<'a, T>(list: &'a List<T>) -> Option<&'a T> { | |
| 811 | match *list { | |
| 812 | Nil => None, | |
| 813 | Cons(ref x, _) => Some(&x), | |
| 814 | } | |
| 815 | } | |
| 816 | ~~~~ | |
| 817 | ||
| 818 | # A Slightly Longer Example | |
| 819 | ||
| 820 | ## Linked List: A Lifetime Original Picture | |
| 821 | ||
| 822 | ~~~~{.rust} | |
| 823 | fn polycephaly<T>(left: &List<T>, right: &List<T>) | |
| 824 | -> Option<(&T, &T)> { | |
| 825 | match (*left, *right) { | |
| 826 | (List::Nil, List::Nil) => None, | |
| 827 | (List::Cons(ref x, _), | |
| 828 | List::Cons(ref y, _)) => Some(y, x) | |
| 829 | } | |
| 830 | } | |
| 831 | ~~~~ | |
| 832 | ||
| 833 | # A Slightly Longer Example | |
| 834 | ||
| 835 | ## You May Find Yourself Living in a Shotgun Shack | |
| 836 | ||
| 837 | ~~~~{.rust} | |
| 838 | fn polycephaly<'l, 'r, T>(left: &'l List<T>, | |
| 839 | right: &'r List<T>) | |
| 840 | -> Option<(&'r T, &'l T)> { | |
| 841 | match *left { | |
| 842 | List::Cons(ref x, _) => match *right { | |
| 843 | List::Cons(ref y, _) => Some((y, x)), | |
| 844 | _ => None, | |
| 845 | }, | |
| 846 | _ => None, | |
| 847 | } | |
| 848 | } | |
| 849 | ~~~~ | |