NOTE阅读文档版本:
语言规约 Cangjie-0.53.18-Spec
具体开发指南 Cangjie-LTS-1.0.4
在阅读 了解仓颉的语言规约时, 难免会涉及到一些仓颉的示例代码, 但 我们对仓颉并不熟悉, 所以可以用 仓颉在线体验 快速验证
有条件当然可以直接 配置 Canjie-SDK
WARNING博主在此之前, 基本只接触过 C/C++语言, 对大多现代语言都没有了解, 所以在阅读过程中遇到相似的概念, 难免会与 C/C++中的相似概念作类比, 见谅
且, 本系列是文档阅读, 而不是仓颉的零基础教学, 所以如果要跟着阅读的话最好有一门编程语言的开发经验
WARNING在阅读仓颉编程语言的开发指南之前, 已经大概阅读了一遍 仓颉编程语言的语言规约, 已经对仓颉编程语言有了一个大概的了解
所以在阅读开发指南时, 不会对类似: 类、函数、结构体、接口等解释起来较为复杂名称 做出解释
此样式内容, 表示文档原文内容
函数
const函数和常量求值
常量求值 允许某些特定形式的表达式 在编译时求值,可以减少程序运行时需要的计算
本章主要介绍常量求值的使用方法与规则
常量求值主要的作用就是 编译器求值, 减少运行时消耗
const上下文与const表达式
const上下文是指const变量初始化表达式,这些表达式始终在编译时求值因此需要对
const上下文中允许的表达式加以限制,避免修改全局状态、I/O等副作用,确保其可以在编译时求值
const表达式具备了可以在编译时求值的能力满足如下规则的表达式是
const表达式:
数值类型、
Bool、Unit、Rune、String类型的字面量(不包含插值字符串)所有元素都是
const表达式的Array字面量(不能是Array类型,可以使用VArray类型),tuple字面量
const变量,const函数形参,const函数中的局部变量
const函数,包含使用const声明的函数名、符合const函数要求的lambda、以及这些函数返回的函数表达式
const函数调用(包含const构造函数),该函数的表达式必须是const表达式,所有实参必须都是const表达式所有参数都是
const表达式的enum构造器调用,和无参数的enum构造器数值类型、
Bool、Unit、Rune、String类型的算术表达式、关系表达式、位运算表达式,所有操作数都必须是const表达式
if、match、try、throw、return、is、as这些表达式内的表达式必须都是
const表达式
const表达式的成员访问(不包含属性的访问),tuple的索引访问
const init和const函数中的this和super表达式
const表达式的const实例成员函数调用,且所有实参必须都是const表达式注意:
当前编译器实现暂不支持
throw作为const表达式使用
仓颉中, 存在const上下文的概念
什么是const上下文呢?
即, 给const变量初始化 所用的表达式
但, 仓颉中 并不是所有表达式都可以给const变量做初始化, 只有const表达式, 才能给const变量做初始化
这也就是说const上下文中, 实际只能出现const表达式, 只有这样才能保证编译时求值
仓颉中对const表达式的定义在文档中已经列出了
有 常用数据类型的字面量, const变量, const函数的形参以及函数体内的局部变量, const函数等等
const函数
const函数是一类特殊的函数,这些函数具备了可以在编译时求值的能力在
const上下文中调用这种函数时,这些函数会在编译时执行计算而在其他非
const上下文,const函数会和普通函数一样在运行时执行下例是一个计算平面上两点距离的
const函数,distance中使用let定义了两个局部变量dx和dy:struct Point {const Point(let x: Float64, let y: Float64) {}}const func distance(a: Point, b: Point) {let dx = a.x - b.xlet dy = a.y - b.y(dx**2 + dy**2)**0.5}main() {const a = Point(3.0, 0.0)const b = Point(0.0, 4.0)const d = distance(a, b)println(d)}编译运行输出:
5.000000
仓颉中的const函数, 在const上下文中调用时, 编译时执行运算
在非const上下文中调用时, const函数就被当作普通函数调用
需要注意:
const函数声明必须使用const修饰全局
const函数和static const函数中只能访问const声明的外部变量,包含const全局变量、const静态成员变量,其他外部变量都不可访问
const init函数和const实例成员函数除了能访问const声明的外部变量,还可以访问当前类型的实例成员变量
const函数中的表达式都必须是const表达式,const init函数除外
const函数中可以使用let、const声明新的局部变量但不支持
var
const函数中的参数类型和返回类型没有特殊规定如果该函数调用的实参不符合
const表达式要求,那这个函数调用不能作为const表达式使用,但仍然可以作为普通表达式使用
const函数不一定都会在编译时执行,例如可以在非const函数中运行时调用
const函数与非const函数重载规则一致数值类型、
Bool、Unit、Rune、String类型 和enum支持定义const实例成员函数对于
struct和class,只有定义了const init才能定义const实例成员函数
class中的const实例成员函数不能是open的
struct中的const实例成员函数不能是mut的另外,接口中也可以定义
const函数,但会受到以下规则限制:
接口中的
const函数,实现类型必须也用const函数才算实现接口接口中的非
const函数,实现类型使用const或非const函数都算实现接口接口中的
const函数与接口的static函数一样,只有在该接口作为泛型约束的时候,受约束的泛型变元或变量才能使用这些const函数在下面的例子中,在接口
I里定义了两个const函数,类A实现了接口I,泛型函数g的形参类型上界是Iinterface I {const func f(): Int64const static func f2(): Int64}class A <: I {public const func f() { 0 }public const static func f2() { 1 }const init() {}}const func g<T>(i: T) where T <: I {return i.f() + T.f2()}main() {println(g(A()))}编译执行上述代码,输出结果为:
1
仓颉中, const函数的就是被const修饰的函数:
const func function() {}不过, const函数的定义存在许多的限制, 具体限制不用太多介绍, 文档中都有列出
const init
如果一个
struct或class定义了const构造器,那么这个struct/class实例可以用在const表达式中
如果当前类型是
class,则不能具有var声明的实例成员变量,否则不允许定义const init如果当前类型具有父类,当前的
const init必须调用父类的const init可以显式调用或者隐式调用无参const init),如果父类没有const init则报错当前类型的实例成员变量如果有初始值,初始值必须要是
const表达式,否则不允许定义const init
const init内可以使用赋值表达式对实例成员变量赋值,除此以外不能有其他赋值表达式
const init与const函数的区别是const init内允许对实例成员变量进行赋值(需要使用赋值表达式)
const init就是类或结构体的const构造函数
如果要定义const init, 那么:
-
不允许存在
var成员变量 -
父类必须也存在
const init -
所有实例成员变量的初始值, 必须是
const表达式