doc: update sum type docs (#5702)
parent
9a4d989188
commit
9e7ba5f138
108
doc/docs.md
108
doc/docs.md
|
@ -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.
|
||||||
|
|
|
@ -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