仓颉函数:定义、调用与进阶特性

目录

1.函数基础:定义与调用

[1.1 函数基本定义语法](#1.1 函数基本定义语法)

[1.2 两种参数类型:非命名 & 命名](#1.2 两种参数类型:非命名 & 命名)

[1.3 函数调用的核心要求](#1.3 函数调用的核心要求)

2.函数的进阶特性

[2.1 函数是一等公民](#2.1 函数是一等公民)

[2.2 嵌套函数](#2.2 嵌套函数)

[2.3 匿名函数:Lambda 表达式](#2.3 匿名函数:Lambda 表达式)

[2.3.1 Lambda 基本语法](#2.3.1 Lambda 基本语法)

[2.3.2 Lambda 代码示例](#2.3.2 Lambda 代码示例)

[2.3.3 尾随 Lambda(语法糖)](#2.3.3 尾随 Lambda(语法糖))


在仓颉语言中,函数是一等公民,不仅支持常规的定义与调用,还具备嵌套、Lambda 表达式、闭包、操作符重载等高级特性,同时提供了 const 函数编译期求值、函数调用语法糖等实用能力,适配全场景开发的灵活需求。

1.函数基础:定义与调用

仓颉使用关键字func 来表示函数定义的开始,func 之后依次是函数名、参数列表【支持非命名参数命名参数(可带默认值)】、可选的函数返回值类型、函数体。

1.1 函数基本定义语法

java 复制代码
// 完整语法:func 函数名(参数列表): 返回值类型 { 函数体 }
func add(a: Int64, b: Int64): Int64 {
    return a + b // 显式return返回值
}

// 省略return:函数体最后一项为表达式,自动作为返回值
func sub(a: Int64, b: Int64): Int64 {
    a - b
}

// 省略返回值类型:编译器自动推导为Int64
func mul(a: Int64, b: Int64) {
    a * b
}

// 无参数、无返回值(默认返回Unit类型)
func sayHello() {
    println("Hello Cangjie!")
}
  • 仓颉函数的返回值类型可选 配置,编译器会根据**return表达式函数体最后一项**自动推导
  • 无返回值的函数默认返回Unit类型,等价于 Java 的void,但Unit是实际的类型,唯一实例为()
  • 函数体中若显式写return ,其表达式类型必须与返回值类型匹配;若省略return,函数体最后一项需为对应类型的表达式

1.2 两种参数类型:非命名 & 命名

一个函数可以拥有 0 个或多个参数,这些参数均定义在函数的参数列表中。根据函数调用时是否需要给定参数名 ,可以将参数列表中的参数分为两类:非命名参数和命名参数。其中命名参数支持设置默认值。

核心规则:

  • 非命名参数 :语法 p: T,调用时直接传值,无需指定参数名;
  • 命名参数 :语法 p!: T ,调用时需写 p: 值 ,仅命名参数可设置默认值**p!: T = 表达式**;
  • 混合参数 :非命名参数必须在前,命名参数在后,不可交替。
java 复制代码
// 混合参数:非命名参数a在前,命名参数b/c在后(c带默认值)
func calc(a: Int64, b!: Int64, c!: Int64 = 10): Int64 {
    a + b * c
}

main(): Int64 {
    // 调用1:全传参,命名参数指定名称
    let res1 = calc(2, b: 3, c: 5) // 2+3*5=17
    // 调用2:命名参数c使用默认值10
    let res2 = calc(2, b: 3) // 2+3*10=32
    // 调用3:命名参数顺序可任意调整
    let res3 = calc(2, c: 2, b: 4) //2+4*2=10
    
    println("res1:${res1}, res2:${res2}, res3:${res3}")
    return 0
}

1.3 函数调用的核心要求

  • 实参类型必须是形参类型的子类型,编译期严格校验;
  • 命名参数调用时必须指定参数名,无默认值的命名参数不可省略;
  • 函数参数为不可变变量 ,函数体内不能对形参赋值(如a = a + 1会编译报错)。

2.函数的进阶特性

2.1 函数是一等公民

仓颉编程语言中,函数是一等公民(first-class citizens),可以作为函数的参数或返回值,也可以赋值给变量。因此函数本身也有类型,称之为函数类型

函数类型 由函数的参数类型返回类型 组成,参数类型和返回类型之间使用**->** 连接。语法为**(参数类型列表) -> 返回值类型**。

java 复制代码
// 定义普通函数
func add(a: Int64, b: Int64): Int64 {
    a + b
}

// 1. 函数赋值给变量:变量类型为函数类型
let f1: (Int64, Int64) -> Int64 = add
// 2. 函数作为参数:形参类型为函数类型
func callFunc(fun: (Int64, Int64) -> Int64, x: Int64, y: Int64): Int64 {
    fun(x, y)
}
// 3. 函数作为返回值:返回值类型为函数类型
func returnFunc(): (Int64, Int64) -> Int64 {
    add
}

main(): Int64 {
    let res1 = f1(10, 20) // 30
    let res2 = callFunc(add, 100, 200) // 300
    let f2 = returnFunc()
    let res3 = f2(1, 2) //3
    
    println("res1:${res1}, res2:${res2}, res3:${res3}")
    return 0
}
  • 函数类型支持类型参数名 ,如(x: Int64, y: Int64) -> Int64,但需统一写或统一不写,不可交替;
  • 函数名本身是表达式,其类型为对应的函数类型,重载函数直接赋值会产生歧义,需显式指定变量类型。

2.2 嵌套函数

定义在函数体内的函数称为嵌套函数 ,其作用域仅限于外部函数,可访问外部函数的变量 / 参数,也可被外部函数返回(结合闭包使用)。

核心特性

  1. 作用域隔离 :嵌套函数的作用域仅限于其所在的外部函数 。嵌套函数可以访问外部函数的变量和参数,但外部函数不能直接访问嵌套函数的内部变量
  2. 生命周期绑定 :每次外部函数调用 时,嵌套函数被创建;外部函数执行完毕后,嵌套函数通常被销毁,除非通过返回或闭包被外部引用。
  3. 可被返回:嵌套函数可作为外部函数的返回值,脱离原作用域后通过闭包继续生效。
java 复制代码
func outerFunc(base: Int64): (Int64) -> Int64 {
    // 嵌套函数:访问外部函数的参数base
    func innerFunc(num: Int64): Int64 {
        num + base
    }
    // 返回嵌套函数
    return innerFunc
}

main(): Int64 {
    // 调用外部函数,base=10,得到嵌套函数实例
    let f = outerFunc(10)
    // 调用嵌套函数,仍可访问base=10
    println(f(5)) // 15
    println(f(8)) // 18
    return 0
}

2.3 匿名函数:Lambda 表达式

Lambda 表达式是无函数名的匿名函数,用于快速定义简短的函数逻辑,可直接调用、赋值给变量、作为函数参数 / 返回值,是仓颉简化代码的核心特性之一。

2.3.1 Lambda 基本语法

{ 参数列表: 参数类型 => 函数体 }

// 简化:参数类型可省略(编译器自动推导),无参数写{ => 函数体 }

核心规则

  • 无论有无参数,=>不可省略尾随 Lambda除外)
  • 不支持显式声明返回值类型,由上下文自动推导
  • 可立即调用,也可赋值给变量后调用

2.3.2 Lambda 代码示例

java 复制代码
main(): Int64 {
    // 1. 带参数的Lambda,显式指定类型
    let add = { a: Int64, b: Int64 => a + b }
    println(add(3, 5)) // 8
    
    // 2. 无参数的Lambda
    let sayHi = { => println("Hi Lambda!") }
    sayHi() // Hi Lambda!
    
    // 3. Lambda立即调用
    let res = { x: Int64, y: Int64 => x * y }(4, 6)
    println(res) //24
    
    // 4. Lambda作为函数参数(结合函数一等公民特性)
    func compute(fun: (Int64) -> Int64, num: Int64) {
        return fun(num)
    }
    let res1 = compute({ n: Int64 => n * n }, 8)
    println(res1) //64

    return 0
}

2.3.3 尾随 Lambda(语法糖)

当函数最后一个形参是函数类型 ,且实参是 Lambda 时,可将 Lambda 移到函数调用的圆括号外 ,称为尾随 Lambda此时可省略 =>,让代码更简洁。

java 复制代码
// 定义函数:最后一个参数为函数类型
func doSomething(a: Int64, fn: (Int64) -> Int64): Int64 {
    fn(a)
}

main(): Int64 {
    // 普通调用
    let res1 = doSomething(5, { n: Int64 => n * 2 }) //10
    // 尾随Lambda:可以把Lambda移出括号,Lambda参数类型可省略(类型推断)
    let res2 = doSomething(5) { n => n * 2 } //10
    // 极致简化:函数只有一个参数,且该参数是函数类型
    func onlyLambda(fn: () -> Unit) { fn() }  // 接收一个无参数、无返回值的函数并在函数体中执行
    onlyLambda { println("尾随Lambda极致简化") }
    
    println("res1:${res1}, res2:${res2}")
    return 0
}

输出结果:

相关推荐
宇木灵14 小时前
考研数学-高中数学-反三角函数与特殊函数day3
笔记·考研·数学·函数
We....3 天前
仓颉语言入门:核心概念与基础数据类型
编程语言·仓颉·仓颉鸿蒙
apcipot_rain5 天前
原神“十盒半价”问题的兹白式建模分析
python·数学·算法·函数·数据科学·原神·数列
_waylau7 天前
跟老卫学仓颉编程语言开发:浮点类型
人工智能·华为·harmonyos·鸿蒙·鸿蒙系统·仓颉
坚果的博客10 天前
cjman:仓颉生态的轻量化工程管理工具
仓颉
_waylau14 天前
跟老卫学仓颉编程语言开发:整数类型
算法·华为·harmonyos·鸿蒙·鸿蒙系统·仓颉
请为小H留灯14 天前
Excel 常用公式大全(带详细步骤):文本→日期→判断→查找→统计→求和
excel·职场·函数·公式·办公常用
星火开发设计20 天前
格式化输入输出:控制输出精度与对齐方式
开发语言·c++·学习·算法·函数·知识
星火开发设计23 天前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识