@@ -1528,12 +1528,9 @@ fn contains(v: &[int], elt: int) -> bool {
1528
1528
1529
1529
# Generics
1530
1530
1531
- ## Generic functions
1532
-
1533
1531
Throughout this tutorial, we've been defining functions that act only on
1534
- single data types. It's a burden to define such functions again and again for
1535
- every type they apply to. Thus, Rust allows functions and datatypes to have
1536
- type parameters.
1532
+ single data types. With type parameters we can also define functions that
1533
+ may be invoked on multiple types.
1537
1534
1538
1535
~~~~
1539
1536
fn map<T, U>(vector: &[T], function: fn(v: &T) -> U) -> ~[U] {
@@ -1545,9 +1542,10 @@ fn map<T, U>(vector: &[T], function: fn(v: &T) -> U) -> ~[U] {
1545
1542
}
1546
1543
~~~~
1547
1544
1548
- When defined with type parameters, this function can be applied to any
1549
- type of vector, as long as the type of ` function ` 's argument and the
1550
- type of the vector's content agree with each other.
1545
+ When defined with type parameters, as denoted by ` <T, U> ` , this
1546
+ function can be applied to any type of vector, as long as the type of
1547
+ ` function ` 's argument and the type of the vector's content agree with
1548
+ each other.
1551
1549
1552
1550
Inside a generic function, the names of the type parameters
1553
1551
(capitalized by convention) stand for opaque types. You can't look
@@ -1558,11 +1556,12 @@ parameter `function()` is supplied with a pointer to a value of type
1558
1556
function works with the broadest set of types possible, since some
1559
1557
types are expensive or illegal to copy and pass by value.
1560
1558
1561
- ## Generic datatypes
1562
-
1563
1559
Generic ` type ` , ` struct ` , and ` enum ` declarations follow the same pattern:
1564
1560
1565
1561
~~~~
1562
+ # use std::map::HashMap;
1563
+ type Set<T> = HashMap<T, ()>;
1564
+
1566
1565
struct Stack<T> {
1567
1566
elements: ~[mut T]
1568
1567
}
@@ -1573,89 +1572,112 @@ enum Maybe<T> {
1573
1572
}
1574
1573
~~~~
1575
1574
1576
- These declarations produce valid types like ` Stack<u8> ` and ` Maybe<int> ` .
1575
+ These declarations produce valid types like ` Set<int> ` , ` Stack<int> `
1576
+ and ` Maybe<int> ` .
1577
1577
1578
- ## Kinds
1578
+ ## Traits
1579
1579
1580
1580
Perhaps surprisingly, the 'copy' (duplicate) operation is not defined
1581
- for all Rust types. Resource types (classes with destructors) cannot be
1582
- copied, and neither can any type whose copying would require copying a
1583
- resource (such as records or unique boxes containing a resource).
1581
+ for all Rust types. Types with user-defined destructors cannot be
1582
+ copied, and neither can types that own other types containing
1583
+ destructors.
1584
+
1585
+ ~~~
1586
+ // Instances of this struct can't be copied, either implicitly
1587
+ // or with the `copy` keyword
1588
+ struct NotCopyable {
1589
+ foo: int,
1590
+
1591
+ drop { }
1592
+ }
1593
+
1594
+ // This owned box containing a NotCopyable is also not copyable
1595
+ let not_copyable_box = ~NotCopyable { foo: 0 };
1596
+ ~~~
1584
1597
1585
1598
This complicates handling of generic functions. If you have a type
1586
1599
parameter ` T ` , can you copy values of that type? In Rust, you can't,
1587
- unless you explicitly declare that type parameter to have copyable
1588
- 'kind'. A kind is a type of type .
1600
+ unless you explicitly declare that type parameter to have the
1601
+ _ trait _ for copying, called ` Copy ` .
1589
1602
1590
1603
~~~~ {.ignore}
1591
1604
// This does not compile
1592
- fn head_bad<T>(v: ~[T]) -> T { v[0] }
1605
+ fn head_bad<T>(v: ~[T]) -> T {
1606
+ copy v[0] // Elements of type T aren't copyable
1607
+ }
1608
+ ~~~~
1609
+
1610
+ ~~~~
1593
1611
// This does
1594
- fn head<T: Copy>(v: ~[T]) -> T { v[0] }
1612
+ fn head<T: Copy>(v: ~[T]) -> T {
1613
+ copy v[0]
1614
+ }
1595
1615
~~~~
1596
1616
1597
1617
When instantiating a generic function, you can only instantiate it
1598
- with types that fit its kinds. So you could not apply ` head ` to a
1599
- resource type. Rust has several kinds that can be used as type bounds:
1600
-
1601
- * ` Copy ` - Copyable types. All types are copyable unless they
1602
- are classes with destructors or otherwise contain
1603
- classes with destructors.
1604
- * ` Send ` - Sendable types. All types are sendable unless they
1605
- contain shared boxes, closures, or other local-heap-allocated
1606
- types.
1607
- * ` Const ` - Constant types. These are types that do not contain
1608
- mutable fields nor shared boxes.
1609
-
1610
- > *** Note:*** Rust type kinds are syntactically very similar to
1611
- > [ traits] ( #traits ) when used as type bounds, and can be
1612
- > conveniently thought of as built-in traits. In the future type
1613
- > kinds will actually be traits that the compiler has special
1614
- > knowledge about.
1615
-
1616
- # Traits
1618
+ with types that implement the correct traits. So you could not apply
1619
+ ` head ` to a type with a destructor.
1620
+
1621
+ While most traits can be defined and implemented by user code, three
1622
+ traits are derived for all applicable types by the compiler, and may
1623
+ not be overridden:
1624
+
1625
+ * ` Copy ` - Types that can be copied, either implicitly, or using the
1626
+ ` copy ` expression. All types are copyable unless they are classes
1627
+ with destructors or otherwise contain classes with destructors.
1628
+
1629
+ * ` Send ` - Sendable (owned) types. All types are sendable unless they
1630
+ contain managed boxes, managed closures, or otherwise managed
1631
+ types. Sendable types may or may not be copyable.
1632
+
1633
+ * ` Const ` - Constant (immutable) types. These are types that do not contain
1634
+ mutable fields.
1635
+
1636
+ > *** Note:*** These three traits were referred to as 'kinds' in earlier
1637
+ > iterations of the language, and often still are.
1617
1638
1618
1639
Traits are Rust's take on value polymorphism—the thing that
1619
1640
object-oriented languages tend to solve with methods and inheritance.
1620
1641
For example, writing a function that can operate on multiple types of
1621
1642
collections.
1622
1643
1623
- > *** Note:*** This feature is very new, and will need a few extensions to be
1624
- > applicable to more advanced use cases.
1625
-
1626
- ## Declaration
1644
+ ## Declaring and implementing traits
1627
1645
1628
- A trait consists of a set of methods. A method is a function that
1646
+ A trait consists of a set of methods, or may be empty, as is the case
1647
+ with ` Copy ` , ` Send ` , and ` Const ` . A method is a function that
1629
1648
can be applied to a ` self ` value and a number of arguments, using the
1630
1649
dot notation: ` self.foo(arg1, arg2) ` .
1631
1650
1632
- For example, we could declare the trait ` to_str ` for things that
1633
- can be converted to a string, with a single method of the same name :
1651
+ For example, we could declare the trait ` Stringable ` for things that
1652
+ can be converted to a string, with a single method:
1634
1653
1635
1654
~~~~
1636
1655
trait ToStr {
1637
- fn to_str() -> ~str;
1656
+ fn to_str(self ) -> ~str;
1638
1657
}
1639
1658
~~~~
1640
1659
1641
- ## Implementation
1642
-
1643
1660
To actually implement a trait for a given type, the ` impl ` form
1644
- is used. This defines implementations of ` to_str ` for the ` int ` and
1661
+ is used. This defines implementations of ` ToStr ` for the ` int ` and
1645
1662
` ~str ` types.
1646
1663
1647
1664
~~~~
1648
- # trait ToStr { fn to_str() -> ~str; }
1665
+ # // FIXME: This example is no good because you can't actually
1666
+ # // implement your own .to_str for int and ~str
1667
+ # trait ToStr { fn to_str(self) -> ~str; }
1649
1668
impl int: ToStr {
1650
- fn to_str() -> ~str { int::to_str(self, 10u) }
1669
+ fn to_str(self ) -> ~str { int::to_str(self, 10u) }
1651
1670
}
1652
1671
impl ~str: ToStr {
1653
- fn to_str() -> ~str { self }
1672
+ fn to_str(self ) -> ~str { self }
1654
1673
}
1674
+
1675
+ # //1.to_str();
1676
+ # //(~"foo").to_str();
1655
1677
~~~~
1656
1678
1657
- Given these, we may call ` 1.to_str() ` to get ` ~ "1"` , or
1658
- ` (~"foo").to_str() ` to get ` ~ "foo"` again. This is basically a form of
1679
+ Given these, we may call ` 1.to_str() ` to get ` "1" ` , or
1680
+ ` (~"foo").to_str() ` to get ` "foo" ` again. This is basically a form of
1659
1681
static overloading—when the Rust compiler sees the ` to_str ` method
1660
1682
call, it looks for an implementation that matches the type with a
1661
1683
method that matches the name, and simply calls that.
0 commit comments