在很多语言中都有 enum 类型,但是不同语言中的 enum 类型的使用方式和表达能力均有所差异,仓颉中的 enum 类型可以理解为函数式编程语言中的代数数据类型。
枚举类型
enum 的定义
1.定义 enum 时需要把它所有可能的取值一一列出,称这些值为 enum 的构造器。多个构造器之间使用 | 进行分隔(第一个构造器之前的 | 是可选的)。构造器可以是有名字的,也可以是没有名字的 ...。
2.每个 enum 中至少存在一个有名字的构造器。
3.仓颉支持同一个 enum 中定义多个同名构造器,但是要求这些构造器的参数个数不同。
4.每个 enum 中最多只有一个没有名字的 ... 构造器,且 ... 只能是最后一个构造器。
5.enum 支持递归定义。
6.enum体中还可以定义一系列成员函数、操作符函数和成员属性,但是要求构造器、成员函数、成员属性之间不能重名。
enum Season { //定义一个季节的枚举
SPRING|SUMMER|AUTUMN|WINTER //无参构造器
|SPRING(Int64)|SUMMER(Int64)|AUTUMN(Int64)|WINTER(Int64)
|SPRING(Int64,String)|SUMMER(Int64,String)|AUTUMN(Int64,String)|WINTER(Int64,String)
|SEASON(Season) // 参数可以递归调用自己
public func getSeasonNaem():String{
'春天'
}
}
enum的使用
当省略类型名时,enum 构造器的名字可能和类型名、变量名、函数名发生冲突。此时必须加上 enum 类型名来使用 enum 构造器,否则只会选择同名的类型、变量、函数定义。
enum Season { //定义一个季节的枚举
SPRING|SUMMER|AUTUMN|WINTER //无参构造器
|SPRING(Int64)|SUMMER(Int64)|AUTUMN(Int64)|WINTER(Int64)
|SPRING(Int64,String)|SUMMER(Int64,String)|AUTUMN(Int64,String)|WINTER(Int64,String)
|SEASON(Season) // 参数可以递归调用自己
|Foo|NAME
public func getSeasonNaem():String{
'春天'
}
}
func Foo(){
println('1')
}
main() {
let NAME =''
let spring = SPRING // 没有同名函数或属性可以省略类型名
let summer = Season.SUMMER(2)
let autum = Season.AUTUMN(3,'秋天')
let winter = Season.SEASON(Season.WINTER)
let foo = Foo //有同名的Foo函数,优先调用了函数
foo()
let name = Season.NAME
}
Option 类型
Option 类型使用 enum 定义,它包含两个构造器:Some 和 None。其中,Some 会携带一个参数,表示有值;None 不带参数,表示无值。当需要表示某个类型可能有值,也可能没有值时,可以选择使用 Option 类型。
enum Option<T> {
| Some(T)
| None
}
Option 类型还有一种简单的写法:在类型名前加 ?。?T 等价于 Option<T>
let a: Option<Int64> = Some(100)
let b: ?Int64 = Some(100)
let c: Option<String> = Some("Hello")
let d: ?String = None
模式概述
对于包含匹配值的 match 表达式,case 之后支持哪些模式决定了 match 表达式的表达能力。类似于switch/case 语句。
match(expr){
case pattern | pattern => block
}
仓颉支持的模式,包括:常量模式、通配符模式、绑定模式、tuple 模式、类型模式和 enum 模式。
func check(value:Int64){
match(value){
case n where n<0 => println('无效')
case n where n<60 => println('不及格')
case n where n<80 => println('良好')
case n where n<100 => println('优秀') //绑定模式
case 100 => println('满分') //常量模式
case _ => println('无效') //通配符模式
}
}
main() {
check(-1) //无效
check(59) //无效
check(66) //良好
check(99) //优秀
check(100) //满分
check(110) //无效
}
没有匹配值的 match 表达式
关键字 match 之后并没有待匹配的表达式,并且 case 之后不再是 pattern,而是类型为 Bool 的表达式(上述代码中的 x > 0 和 x < 0)或者 _(表示 true)。
func check2(value:Int64){
match{
case value<0 => println('无效')
case value<60 => println('不及格')
case value<80 => println('良好')
case value<100 => println('优秀') //绑定模式
case value==100 => println('满分') //常量模式
case _ => println('无效') //通配符模式
}
}
main() {
let a = 1
let s = match{
case a>=0 => '正数'
case a<0 => '负数'
case _ => '无法判断'
}
println(s) // 正数
check2(100) //满分
}
模式在for in 表达式中使用
使用通配符模式
变量定义时使用了通配符模式,表示定义了一个没有名字的变量,循环中不能访问元素的值。
main() {
let _ = 100
for (_ in 1..5) {
print('0 ') //0 0 0 0
}
}
变量定义和 for in 表达式中使用绑定模式
main() {
let i = 100
for (i in 1..5) {
print(i) //1234
}
}
案例使用
定义一个运算枚举,操作符重载,实现枚举的基础运算。
enum Expr {
Num(Float64) |
Add(Expr, Expr) | Sub(Expr, Expr) | Mul(Expr, Expr) | Div(Expr, Expr)
public func calc(): Float64 {
match(this) {
case Num(number) => number
case Add(a, b) => a.calc() + b.calc()
case Sub(a, b) => a.calc() - b.calc()
case Mul(a, b) => a.calc() * b.calc()
case Div(a, b) => a.calc() / b.calc()
}
}
public operator func +(that: Expr): Expr {
return Add(this, that)
}
public operator func -(that: Expr): Expr {
return Sub(this, that)
}
public operator func *(that: Expr): Expr {
return Mul(this, that)
}
public operator func /(that: Expr): Expr {
return Div(this, that)
}
}
main() {
let expr = Num(1.0) + Num(2.0) * Num(3.0) - Num(6.0) / Num(3.0) //1+2*3-6/3
println(expr.calc()) //5.000000
}