1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*! Directed Type Conversion
This trait is an accessory to [`From`] and [`Into`]. It works by moving the
destination type from the trait name (`Into<Target>::into`) into the method name
(`Conv::conv::<Target>`). This change makes `Into<_>` the correct trait to use
in trait bounds and `.conv::<_>` the correct method to use in expressions.
A `conv::<T>` method is automatically available whenever an `Into<T>`
implementation exists for a type. `Into<T>` is most commonly implemented by
taking advantage of the reflexive blanket implentation using `From`, but can
also be manually implemented as desired.
`.into()` cannot be used in intermediate expressions, because it is impossible
for the compiler’s type engine to select a unique `Into<T>` implementation. This
means that expressions like `v.into().use()` will never compile. Users can
replace `.into()` with `.conv::<Dest>()` in order to inform the compiler of the
type of the expression after the conversion, and make compilation succeed.
`Conv` cannot be used in trait bounds, because the trait itself is not generic.
All `Sized` types implement `Conv` by default, so specifying that a type must be
`Conv` adds no information to the solver.
# Examples
## Conversion as methods
Conversion with `.into()` will fail to compile, even with the type annotation:
```rust,ignore
let s: String = "static".into().clone();
// ^^^^^^^^^^^^^^^ cannot infer type for `T`
// note: type must be known at this point
```
while the equivalent code with `.conv::<_>` does compile:
```rust
# use wyz::conv::Conv;
let s = "static".conv::<String>().clone();
```
## Conversion as traits
Bounding a type with `Conv` will not compile, because the trait itself gives no
information:
```rust,ignore
# use wyz::conv::Conv;
fn lift<T: Conv>(src: T) -> String {
src.conv::<String>().clone()
// ^^^^ the trait `From<T>` is not implemented for `String`
// help: consider adding a `where String: From<T>` bound
// note: required because of the requirements on the impl of `Into<String>` for `T`
}
```
This can be fixed by adding the stated clause, or by using `Into` as the trait
bound:
```rust
# use wyz::conv::Conv;
fn lift<T: Into<String>>(src: T) -> String {
src.conv::<String>().clone()
}
```
The `Into<T>` trait bound makes available both the `Into::<T>::into` method and
the `Conv::conv::<T>` method.
[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
[`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html
!*/
/** Directed Type Conversion
This trait is an accessory to [`From`] and [`Into`]. It works by moving the
destination type from the trait name (`Into<Target>::into`) into the method name
(`Conv::conv::<Target>`). This change makes `Into<_>` the correct trait to use
in trait bounds and `.conv::<_>` the correct method to use in expressions.
A `conv::<T>` method is automatically available whenever an `Into<T>`
implementation exists for a type. `Into<T>` is most commonly implemented by
taking advantage of the reflexive blanket implentation using `From`, but can
also be manually implemented as desired.
`.into()` cannot be used in intermediate expressions, because it is impossible
for the compiler’s type engine to select a unique `Into<T>` implementation. This
means that expressions like `v.into().use()` will never compile. Users can
replace `.into()` with `.conv::<Dest>()` in order to inform the compiler of the
type of the expression after the conversion, and make compilation succeed.
`Conv` cannot be used in trait bounds, because the trait itself is not generic.
All `Sized` types implement `Conv` by default, so specifying that a type must be
`Conv` adds no information to the solver.
# Examples
## Conversion as methods
Conversion with `.into()` will fail to compile, even with the type annotation:
```rust,ignore
let s: String = "static".into().clone();
// ^^^^^^^^^^^^^^^ cannot infer type for `T`
// note: type must be known at this point
```
while the equivalent code with `.conv::<_>` does compile:
```rust
# use wyz::conv::Conv;
let s = "static".conv::<String>().clone();
```
## Conversion as traits
Bounding a type with `Conv` will not compile, because the trait itself gives no
information:
```rust,ignore
# use wyz::conv::Conv;
fn lift<T: Conv>(src: T) -> String {
src.conv::<String>().clone()
// ^^^^ the trait `From<T>` is not implemented for `String`
// help: consider adding a `where String: From<T>` bound
// note: required because of the requirements on the impl of `Into<String>` for `T`
}
```
This can be fixed by adding the clause `where String: From<T>`, or by using the
bound `Into`:
```rust
# use wyz::conv::Conv;
fn lift<T: Into<String>>(src: T) -> String {
src.conv::<String>().clone()
}
```
The `Into<T>` trait bound makes available both the `Into::<T>::into` method and
the `Conv::conv::<T>` method.
[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
[`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html
**/