仓颉编程入门:枚举类型和模式匹配

在很多语言中都有 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
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容