doc: update sum type docs (#5702)
parent
9a4d989188
commit
9e7ba5f138
106
doc/docs.md
106
doc/docs.md
|
@ -1196,71 +1196,85 @@ println(color) // "1" TODO: print "green"?
|
|||
|
||||
### Sum types
|
||||
|
||||
A sum type instance can hold a value of several different types. Use the `type`
|
||||
keyword to declare a sum type:
|
||||
|
||||
```v
|
||||
type Expr = BinaryExpr | UnaryExpr | IfExpr
|
||||
struct Moon {}
|
||||
struct Mars {}
|
||||
struct Venus {}
|
||||
|
||||
struct BinaryExpr{ ... }
|
||||
struct UnaryExpr{ ... }
|
||||
struct IfExpr{ ... }
|
||||
type World = Moon | Mars | Venus
|
||||
|
||||
fn (mut p Parser) expr(precedence int) Expr {
|
||||
match p.tok {
|
||||
.key_if { return IfExpr{} }
|
||||
...
|
||||
else { return BinaryExpr{} }
|
||||
sum := World(Moon{})
|
||||
```
|
||||
|
||||
To check whether a sum type instance holds a certain type, use `sum is Type`.
|
||||
To cast a sum type to one of its variants you use `sum as Type`:
|
||||
|
||||
```v
|
||||
fn (m Mars) dust_storm() bool
|
||||
|
||||
fn main() {
|
||||
mut w := World(Moon{})
|
||||
assert w is Moon
|
||||
|
||||
w = Mars{}
|
||||
// use `as` to access the Mars instance
|
||||
mars := w as Mars
|
||||
if mars.dust_storm() {
|
||||
println('bad weather!')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
fn gen(expr Expr) {
|
||||
match expr {
|
||||
IfExpr { gen_if(expr) } // `expr` is cast to the matched type automatically
|
||||
...
|
||||
You can also use `match` to determine the variant:
|
||||
|
||||
```v
|
||||
fn open_parachutes(n int)
|
||||
|
||||
fn land(w World) {
|
||||
match w {
|
||||
Moon {} // no atmosphere
|
||||
Mars {
|
||||
// light atmosphere
|
||||
open_parachutes(3)
|
||||
}
|
||||
Venus {
|
||||
// heavy atmosphere
|
||||
open_parachutes(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_if(expr IfExpr) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
To check whether a sum type is a certain type, use `is`:
|
||||
`match` must have a pattern for each variant or have an `else` branch.
|
||||
|
||||
```v
|
||||
println(expr is IfExpr)
|
||||
```
|
||||
|
||||
To cast a sum type to one of its variants you use `as`:
|
||||
|
||||
```v
|
||||
bin_expr := expr as BinaryExpr
|
||||
```
|
||||
|
||||
You can also use match to determine the variant and cast to it at the same time.
|
||||
There are 3 ways to access the cast variant inside a match branch:
|
||||
- the `it` variable
|
||||
There are 2 ways to access the cast variant inside a match branch:
|
||||
- the shadowed match variable
|
||||
- using `as` to specify a variable name
|
||||
|
||||
```v
|
||||
fn binary_expr(bx BinaryExpr) {...}
|
||||
fn unary_expr(ux UnaryExpr) {...}
|
||||
fn if_expr(ix IfExpr) {...}
|
||||
fn (m Moon) moon_walk()
|
||||
fn (m Mars) shiver()
|
||||
fn (v Venus) sweat()
|
||||
|
||||
// using `it`
|
||||
match expr {
|
||||
BinaryExpr { binary_expr(it) }
|
||||
...
|
||||
fn pass_time(w World) {
|
||||
match w {
|
||||
// using the shadowed match variable, in this case `w`
|
||||
Moon { w.moon_walk() }
|
||||
Mars { w.shiver() }
|
||||
else {}
|
||||
}
|
||||
// using the shadowed variable, in this case `expr`
|
||||
match expr {
|
||||
UnaryExpr { unary_expr(expr) }
|
||||
...
|
||||
// using `as` to specify a variable name
|
||||
match w as expr {
|
||||
Venus { expr.sweat() }
|
||||
else {
|
||||
// w is of type World
|
||||
assert w !is Venus
|
||||
}
|
||||
// using `as` to specify a variable
|
||||
match expr as actual_expr {
|
||||
IfExpr { if_expr(actual_expr) }
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: shadowing only works when the match expression is a variable. It will not work on struct fields, arrays indexing, or map key lookup.
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Example of sum types
|
||||
// Models a landing craft leaving orbit and landing on a world
|
||||
import rand
|
||||
import time
|
||||
|
||||
struct Moon {
|
||||
}
|
||||
|
||||
struct Mars {
|
||||
}
|
||||
fn (m Mars) dust_storm() bool {
|
||||
return rand.int() >= 0
|
||||
}
|
||||
|
||||
struct Venus {
|
||||
}
|
||||
|
||||
type World = Moon | Mars | Venus
|
||||
|
||||
struct Lander {
|
||||
}
|
||||
fn (l Lander) deorbit() {
|
||||
println('leaving orbit')
|
||||
}
|
||||
fn (l Lander) open_parachutes(n int) {
|
||||
println('opening $n parachutes')
|
||||
}
|
||||
|
||||
fn wait() {
|
||||
println('waiting...')
|
||||
time.sleep(1)
|
||||
}
|
||||
|
||||
fn (l Lander) land(w World) {
|
||||
if w is Mars {
|
||||
m := w as Mars
|
||||
for m.dust_storm() {
|
||||
wait()
|
||||
}
|
||||
}
|
||||
l.deorbit()
|
||||
match w {
|
||||
Moon {} // no atmosphere
|
||||
Mars {
|
||||
// light atmosphere
|
||||
l.open_parachutes(3)
|
||||
}
|
||||
Venus {
|
||||
// heavy atmosphere
|
||||
l.open_parachutes(1)
|
||||
}
|
||||
}
|
||||
println('landed')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
l := Lander {}
|
||||
l.land(Venus{})
|
||||
l.land(Mars{})
|
||||
}
|
Loading…
Reference in New Issue