doc: update sum type docs (#5702)

pull/5710/head
Nick Treleaven 2020-07-06 17:09:38 +01:00 committed by GitHub
parent 9a4d989188
commit 9e7ba5f138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 47 deletions

View File

@ -1196,71 +1196,85 @@ println(color) // "1" TODO: print "green"?
### Sum types ### Sum types
A sum type instance can hold a value of several different types. Use the `type`
keyword to declare a sum type:
```v ```v
type Expr = BinaryExpr | UnaryExpr | IfExpr struct Moon {}
struct Mars {}
struct Venus {}
struct BinaryExpr{ ... } type World = Moon | Mars | Venus
struct UnaryExpr{ ... }
struct IfExpr{ ... }
fn (mut p Parser) expr(precedence int) Expr { sum := World(Moon{})
match p.tok { ```
.key_if { return IfExpr{} }
...
else { return BinaryExpr{} }
}
}
fn gen(expr Expr) { To check whether a sum type instance holds a certain type, use `sum is Type`.
match expr { To cast a sum type to one of its variants you use `sum as Type`:
IfExpr { gen_if(expr) } // `expr` is cast to the matched type automatically
...
}
}
fn gen_if(expr IfExpr) { ```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!')
}
} }
``` ```
To check whether a sum type is a certain type, use `is`: You can also use `match` to determine the variant:
```v ```v
println(expr is IfExpr) 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)
}
}
}
``` ```
To cast a sum type to one of its variants you use `as`: `match` must have a pattern for each variant or have an `else` branch.
```v There are 2 ways to access the cast variant inside a match branch:
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
- the shadowed match variable - the shadowed match variable
- using `as` to specify a variable name - using `as` to specify a variable name
```v ```v
fn binary_expr(bx BinaryExpr) {...} fn (m Moon) moon_walk()
fn unary_expr(ux UnaryExpr) {...} fn (m Mars) shiver()
fn if_expr(ix IfExpr) {...} fn (v Venus) sweat()
// using `it` fn pass_time(w World) {
match expr { match w {
BinaryExpr { binary_expr(it) } // using the shadowed match variable, in this case `w`
... Moon { w.moon_walk() }
} Mars { w.shiver() }
// using the shadowed variable, in this case `expr` else {}
match expr { }
UnaryExpr { unary_expr(expr) } // using `as` to specify a variable name
... match w as expr {
} Venus { expr.sweat() }
// using `as` to specify a variable else {
match expr as actual_expr { // w is of type World
IfExpr { if_expr(actual_expr) } assert w !is Venus
... }
} }
}
``` ```
Note: shadowing only works when the match expression is a variable. It will not work on struct fields, arrays indexing, or map key lookup. Note: shadowing only works when the match expression is a variable. It will not work on struct fields, arrays indexing, or map key lookup.

60
examples/lander.v 100644
View File

@ -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{})
}