@@ -3620,6 +3620,182 @@ guide](http://doc.rust-lang.org/guide-pointers.html#rc-and-arc).
3620
3620
3621
3621
# Generics
3622
3622
3623
+ Sometimes, when writing a function or data type, we may want it to work for
3624
+ multiple types of arguments. For example, remember our ` OptionalInt ` type?
3625
+
3626
+ ``` {rust}
3627
+ enum OptionalInt {
3628
+ Value(int),
3629
+ Missing,
3630
+ }
3631
+ ```
3632
+
3633
+ If we wanted to also have an ` OptionalFloat64 ` , we would need a new enum:
3634
+
3635
+ ``` {rust}
3636
+ enum OptionalFloat64 {
3637
+ Valuef64(f64),
3638
+ Missingf64,
3639
+ }
3640
+ ```
3641
+
3642
+ This is really unfortunate. Luckily, Rust has a feature that gives us a better
3643
+ way: generics. Generics are called ** parametric polymorphism** in type theory,
3644
+ which means that they are types or functions that have multiple forms ("poly"
3645
+ is multiple, "morph" is form) over a given parameter ("parametric").
3646
+
3647
+ Anyway, enough with type theory declarations, let's check out the generic form
3648
+ of ` OptionalInt ` . It is actually provided by Rust itself, and looks like this:
3649
+
3650
+ ``` rust
3651
+ enum Option <T > {
3652
+ Some (T ),
3653
+ None ,
3654
+ }
3655
+ ```
3656
+
3657
+ The ` <T> ` part, which you've seen a few times before, indicates that this is
3658
+ a generic data type. Inside the declaration of our enum, wherever we see a ` T ` ,
3659
+ we substitute that type for the same type used in the generic. Here's an
3660
+ example of using ` Option<T> ` , with some extra type annotations:
3661
+
3662
+ ``` {rust}
3663
+ let x: Option<int> = Some(5i);
3664
+ ```
3665
+
3666
+ In the type declaration, we say ` Option<int> ` . Note how similar this looks to
3667
+ ` Option<T> ` . So, in this particular ` Option ` , ` T ` has the value of ` int ` . On
3668
+ the right hand side of the binding, we do make a ` Some(T) ` , where ` T ` is ` 5i ` .
3669
+ Since that's an ` int ` , the two sides match, and Rust is happy. If they didn't
3670
+ match, we'd get an error:
3671
+
3672
+ ``` {rust,ignore}
3673
+ let x: Option<f64> = Some(5i);
3674
+ // error: mismatched types: expected `core::option::Option<f64>`
3675
+ // but found `core::option::Option<int>` (expected f64 but found int)
3676
+ ```
3677
+
3678
+ That doesn't mean we can't make ` Option<T> ` s that hold an ` f64 ` ! They just have to
3679
+ match up:
3680
+
3681
+ ``` {rust}
3682
+ let x: Option<int> = Some(5i);
3683
+ let y: Option<f64> = Some(5.0f64);
3684
+ ```
3685
+
3686
+ This is just fine. One definition, multiple uses.
3687
+
3688
+ Generics don't have to only be generic over one type. Consider Rust's built-in
3689
+ ` Result<T, E> ` type:
3690
+
3691
+ ``` {rust}
3692
+ enum Result<T, E> {
3693
+ Ok(T),
3694
+ Err(E),
3695
+ }
3696
+ ```
3697
+
3698
+ This type is generic over _ two_ types: ` T ` and ` E ` . By the way, the capital letters
3699
+ can be any letter you'd like. We could define ` Result<T, E> ` as:
3700
+
3701
+ ``` {rust}
3702
+ enum Result<H, N> {
3703
+ Ok(H),
3704
+ Err(N),
3705
+ }
3706
+ ```
3707
+
3708
+ if we wanted to. Convention says that the first generic parameter should be
3709
+ ` T ` , for 'type,' and that we use ` E ` for 'error.' Rust doesn't care, however.
3710
+
3711
+ The ` Result<T, E> ` type is intended to
3712
+ be used to return the result of a computation, and to have the ability to
3713
+ return an error if it didn't work out. Here's an example:
3714
+
3715
+ ``` {rust}
3716
+ let x: Result<f64, String> = Ok(2.3f64);
3717
+ let y: Result<f64, String> = Err("There was an error.".to_string());
3718
+ ```
3719
+
3720
+ This particular Result will return an ` int ` if there's a success, and a
3721
+ ` String ` if there's a failure. Let's write a function that uses ` Result<T, E> ` :
3722
+
3723
+ ``` {rust}
3724
+ fn square_root(x: f64) -> Result<f64, String> {
3725
+ if x < 0.0f64 { return Err("x must be positive!".to_string()); }
3726
+
3727
+ Ok(x * (1.0f64 / 2.0f64))
3728
+ }
3729
+ ```
3730
+
3731
+ We don't want to take the square root of a negative number, so we check
3732
+ to make sure that's true. If it's not, then we return an ` Err ` , with a
3733
+ message. If it's okay, we return an ` Ok ` , with the answer.
3734
+
3735
+ Why does this matter? Well, remember how ` match ` does exhaustive matches?
3736
+ Here's how this function gets used:
3737
+
3738
+ ``` {rust}
3739
+ # fn square_root(x: f64) -> Result<f64, String> {
3740
+ # if x < 0.0f64 { return Err("x must be positive!".to_string()); }
3741
+ # Ok(x * (1.0f64 / 2.0f64))
3742
+ # }
3743
+ let x = square_root(25.0f64);
3744
+
3745
+ match x {
3746
+ Ok(x) => println!("The square root of 25 is {}", x),
3747
+ Err(msg) => println!("Error: {}", msg),
3748
+ }
3749
+ ```
3750
+
3751
+ The ` match enforces that we handle the ` Err` case. In addition, because the
3752
+ answer is wrapped up in an ` Ok ` , we can't just use the result without doing
3753
+ the match:
3754
+
3755
+ ``` {rust,ignore}
3756
+ let x = square_root(25.0f64);
3757
+ println!("{}", x + 2.0f64); // error: binary operation `+` cannot be applied
3758
+ // to type `core::result::Result<f64,collections::string::String>`
3759
+ ```
3760
+
3761
+ This function is great, but there's one other problem: it only works for 64 bit
3762
+ floating point values. What if we wanted to handle 32 bit floating point as
3763
+ well? We'd have to write this:
3764
+
3765
+ ``` {rust}
3766
+ fn square_root32(x: f32) -> Result<f32, String> {
3767
+ if x < 0.0f32 { return Err("x must be positive!".to_string()); }
3768
+
3769
+ Ok(x * (1.0f32 / 2.0f32))
3770
+ }
3771
+ ```
3772
+
3773
+ Bummer. What we need is a ** generic function** . Luckily, we can write one!
3774
+ However, it won't _ quite_ work yet. Before we get into that, let's talk syntax.
3775
+ A generic version of ` square_root ` would look something like this:
3776
+
3777
+ ``` {rust,ignore}
3778
+ fn square_root<T>(x: T) -> Result<T, String> {
3779
+ if x < 0.0 { return Err("x must be positive!".to_string()); }
3780
+
3781
+ Ok(x * (1.0 / 2.0))
3782
+ }
3783
+ ```
3784
+
3785
+ Just like how we had ` Option<T> ` , we use a similar syntax for ` square_root<T> ` .
3786
+ We can then use ` T ` inside the rest of the signature: ` x ` has type ` T ` , and half
3787
+ of the ` Result ` has type ` T ` . However, if we try to compile that example, we'll get
3788
+ an error:
3789
+
3790
+ ``` {notrust,ignore}
3791
+ error: binary operation `<` cannot be applied to type `T`
3792
+ ```
3793
+
3794
+ Because ` T ` can be _ any_ type, it may be a type that doesn't implement ` < ` ,
3795
+ and therefore, the first line would be wrong. What do we do?
3796
+
3797
+ To fix this example, we need to learn about another Rust feature: traits.
3798
+
3623
3799
# Traits
3624
3800
3625
3801
# Operators and built-in Traits
0 commit comments