您的位置:首页 > 新闻 > 资讯 > 代理产品_室内设计联盟官网入口网页_近期的重大新闻_江苏网站建站系统哪家好

代理产品_室内设计联盟官网入口网页_近期的重大新闻_江苏网站建站系统哪家好

2025/6/9 14:28:58 来源:https://blog.csdn.net/m0_37170006/article/details/143330393  浏览:    关键词:代理产品_室内设计联盟官网入口网页_近期的重大新闻_江苏网站建站系统哪家好
代理产品_室内设计联盟官网入口网页_近期的重大新闻_江苏网站建站系统哪家好

标识符

在仓颉编程语言中,开发者可以给一些程序元素命名,这些名字也被称为“标识符”(变量名称),标识符分为普通标识符和原始标识。

普通标识符

普通标识符不能和仓颉关键字相同,可以取自以下两类字符序列:

  • 由 XID_Start 字符开头,后接任意长度的 XID_Continue 字符
  • 由一个_开头,后接至少一个 XID_Continue 字符

合法的普通标识符:

abc
_abc
abc_
a1b2c3
a_b_c
a1_b2_c3
仓颉
__こんにちは

不合法的普通标识符:

ab&c  // 使用了非法字符 “&”
3abc  // 数字不能出现在头部
while // 不能使用仓颉关键字

原始标识符

原始标识符是在普通标识符或仓颉关键字的外面加上一对反引号,主要用于将仓颉关键字作为标识符的场景。

合法的原始标识符:

`abc`
`_abc`
`a1b2c3`
`if`
`while`
`à֮̅̕b`

不合法的原始标识符

`ab&c`
`3abc`

程序结构

仓颉语言接口DevEco Studio工具中,在新建文件的时候文件夹右击New>Cangjie File,即可新建一个后缀是.cj的文本文件并编写仓颉程序。
仓颉在编写程序时跟JS很像,作为前端小伙伴理解会很快。所以在编写程序时,需要注意以下几点:

  • 顶层作用域中,可以的变量、函数和自定义类型(如 struct、class、enum 和 interface 等),变量和函数分别被称为全局变量全局函数
  • 将仓颉程序编译为可执行文件,需在顶层作用域中定义一个 main 函数作为程序入口,可以有 Array 类型的参数,也可以没有参数,它的返回值类型可以是整数类型或 Unit 类型;
  • 非顶层作用域不能定义上述自定义类型,但可以定义变量和函数,分别被称为局部变量局部函数
  • 对于定义在自定义类型中的变量和函数,称之为成员变量成员函数
// example.cj
let a = 2023
func b() {}
struct C {}
class D {}
enum E { F | G }main() {println(a)
}

注意
enum 和 interface 中仅支持定义成员函数,不支持定义成员变量。

案例:官方案例在顶层作用域定义了全局函数 a 和自定义类型 A,在函数 a 中定义了局部变量 b 和局部函数 c,在自定义类型 A 中定义了成员变量 b 和成员函数 c。

// example.cj
func a() {let b = 2023func c() {println(b)}c()
}class A {let b = 2024public func c() {println(b)}
}main() {a()A().c()
}

运行以上程序,将输出:

2023
2024

是不是跟学习JS很像,不过仓颉是强类型语言。但是没有关系,只要你会JS/TS,你就可以很快上手仓颉。

仓颉变量

变量定义的具体形式为:

修饰符 变量名: 变量类型 = 初始值

修饰符可以一个或者多个,目前支持的修饰符有:

  • 可变性修饰符:let 与 var 前端同学非常熟悉,分别对应不可变和可变属性,这里前端同学要注意一下,仓颉定义var是可变,let不可变变量。跟JS/TS不一样。
  • 可见性修饰符:private 与 public 等,影响全局变量和成员变量的可引用范围
  • 静态性修饰符:static,影响成员变量的存储和引用方式
main() {let a: Int64 = 20var b: Int64 = 12b = 23println("${a}${b}")
}// 输出结构 2023

如果尝试修改不可变变量,编译时会报错,例如:

main() {let pi: Float64 = 3.14159pi = 2.71828 // Error, cannot assign to immutable value
}

在定义全局变量和静态成员变量时必须初始化,否则编译会报错,例如:

// example.cj
let global: Int64 // Error, variable in top-level scope must be initialized
class Player {static let score: Int32 // Error, static variable 'score' needs to be initialized when declaring
}

值类型和引用类型变量

这里对于前端和编程基础的同学很容易理解,前端同学可以把值类型理解为基本类型,比如Int、Float、String等,引用类型理解为对象类型,比如Array、Map、Set等。
对于零基础的同学,对于值类型和引用类型的区别,我们可以通过以下代码来理解:

值类型变量对它所绑定的数据/存储空间是独占的,而引用类型变量所绑定的数据/存储空间可以和其他引用类型变量共享。

差异:

  1. 值类型变量赋值时,是拷贝操作,原来绑定的数被覆写。引用类型变量赋值时,只是改变了引用关系,原来绑定的数据/存储空间不会被覆写。
  2. 用 let 定义的变量,要求变量被初始化后都不能再赋值。对于引用类型,这只是限定了引用关系不可改变,但是所引用的数据是可以被修改的。

JS的变量性质非常像是,可以无缝理解。

仓颉编程语言,class 和 Array 等类型属于引用类型,其他基础数据类型和 struct 等类型属于值类型。

例如,以下程序演示了 struct 和 class 类型变量的行为差异:

struct Copy {var data = 2012
}class Share {var data = 2012
}main() {let c1 = Copy()var c2 = c1c2.data = 2023println("${c1.data}, ${c2.data}")let s1 = Share()let s2 = s1s2.data = 2023println("${s1.data}, ${s2.data}")
}// 运行后,输出结果
// 2012, 2023
// 2023, 2023

如果将以上程序中的 var c2 = c1 改成 let c2 = c1,则编译会报错,例如:

struct Copy {var data = 2012
}main() {let c1 = Copy()let c2 = c1c2.data = 2023 // Error, cannot assign to immutable value
}

作用域

仓颉的作用域也跟JS非常像,前端同学可以把作用域理解为作用域链

  1. 当前作用域中定义的程序元素与名字的绑定关系,在当前作用域和其内层作用域中是有效的,可以通过此名字直接访问对应的程序元素。
  2. 内层作用域中定义的程序元素与名字的绑定关系,在外层作用域中无效。
  3. 内层作用域可以使用外层作用域中的名字重新定义绑定关系,根据规则 1,此时内层作用域中的命名相当于遮盖了外层作用域中的同名定义,对此我们称内层作用域的级别比外层作用域的级别高。

仓颉语言中 “{}” 包围的代码块,称为一个作用域。在一个仓颉源文件中,不被任何大括号“{}”包围的代码,它们所属的作用域被称为“顶层作用域”,即当前文件中“最外层”的作用域,按上述规则,其作用域级别最低。

例如在以下名为 test.cj 的仓颉源文件里,在顶层作用域中定义了名字 element,它和字符串“仓颉”绑定,而 main 和 if 引导的代码块中也定义了名字 element,分别对应整数 9 和整数 2023。由上述作用域规则,在第 4 行,element 的值为“仓颉”,在第 8 行,element 的值为 2023,在第 10 行,element 的值为 9。

// test.cj
let element = "仓颉"
main() {println(element)let element = 9if (element > 0) {let element = 2023println(element)}println(element)
}/* 
运行以上程序,将输出:
仓颉
2023
9
*/

总结
从变量到作用域跟Javascript非常相识,但是也要注意let和var的区别。

修饰符可以是一个或者多个,目前支持的修饰符有:let、var 等,分别对应不可变和可变属性,这里前端同学要注意一下,仓颉定义var是可变,let不可变变量。跟JS/TS不一样。public、private等,影响全局变量和成员变量的可引用范围,static,影响成员变量的存储和引用方式。

在仓颉里,class是引用类型,所以在赋值的时候,是引用赋值。struct是值类型,所以在赋值的时候,是拷贝赋值。

表达式

仓颉不仅有传统的算术运算表达式,还有条件表达式、循环表达式和 try 表达式等
仓颉是强类型的编程语言,所以仓颉表达式不仅可求值,还有确定的类型。

条件表达式

条件表达式分为 if 表达式和 if-let 表达式两种,它们的值与类型需要根据使用场景来确定。

if 表达式

基本形式:

if (条件) {分支 1
} else {分支 2
}

其中“条件”是布尔类型表达式,“分支 1”和“分支 2”是两个代码块。

注意:
仓颉编程语言是强类型的,if 表达式的条件只能是布尔类型,不能使用整数或浮点数等类型,和 C 语言和Javascript等不同,仓颉不以条件取值是否为 0 作为分支选择依据

例如以下程序将编译报错:

main() {let number = 1if (number) { // Error, mismatched typesprintln("非零数")}
}
if 表达式的值和类型,需要根据使用形式与场景来确定
  • 当含 else 分支的 if 表达式被求值时,需要根据求值上下文确定 if 表达式的类型:
    • 如果上下文明确要求值类型为 T,则 if 表达式各分支代码块的类型必须是 T 的子类型,这时 if 表达式的类型被确定为 T,如果不满足子类型约束,编译会报错。
    • 如果上下文没有明确的类型要求,则 if 表达式的类型是其各分支代码块类型的最小公共父类型,如果最小公共父类型不存在,编译会报错。
      如果编译通过,则 if 表达式的值就是所执行分支代码块的值。
  • 如果含 else 分支的 if 表达式没有被求值,在这种场景里,开发者一般只想在不同分支里做不同操作,不会关注各分支最后一个表达式的值与类型,为了不让上述类型检查规则影响这一思维习惯,仓颉规定这种场景下的 if 表达式类型为 Unit、值为 (),且各分支不参与上述类型检查。
  • 最后就是没有 else is的 类型是Unit、值是()

最小共公父类型:多个变量的类型的最小共公父类型,例如:Int8、Int16、Int32、Int64 的最小共公父类型是 Int32。

一下就是if模拟的换算过程:

main() {let zero: Int8 = 0let one: Int8 = 1let voltage = 5.0let bit = if (voltage < 2.5) {zero} else {one}
}

循环表达式

for-in表达式

for (迭代变量 in 序列) {循环体
}
  • 迭代变量:“迭代变量”是单个标识符或由多个标识符构成的元组,用于绑定每轮遍历中由迭代器指向的数据
  • 序列:一个表达式,遍历表达式的值,类型必须扩展了迭代接口Iterable<T>,例如:数组、字符串、元组等
  • 循环体:代码块

for-in 表达式可以遍历区间类型实例: 例如:

main(){var sum = 0;for (i in 1..=100) {sum +=i}println("总数是${sum}")
}
// 输入
// 总数是5050

遍历元组类型:例如:

main(){let array = [(1, 2), (3, 4), (5, 6)]for ((a, b) in array) {println("${a}, ${b}")}
}

结果:

1, 2
3, 4
5, 6
迭代变量不可修改
main(){for (i in 1..10){i = i * 10 // 这里的i是只读的,不能修改。会报错println(i) }
}
使用通配符 _

在一些应用场景中,只需要循环,并不使用迭代变量,这时可以用通配符 _ 代替迭代变量,例如:

main() {var number = 2for (_ in 0..5) {number *= number}println(number)
}

输出:

4294967296
where条件

为循环遍历,可能需要直接跳过、进入下一轮循环。在所遍历的“序列”之后用 where 关键字引导一个布尔表达式,只有当布尔表达式的值为 true 时,才会进入下一轮循环。例如:

for (i in 0..8 where i % 2 == 1) { // i 为奇数才会执行循环体println(i)
}

输出:

1
3
5
7

while表达式

基本形式为:

while (条件) {循环体
}

使用 while 计算数字 2 的平方根:

main(){var root = 0.0var min = 1.0var max = 2.0var error = 1.0let tolerance = 0.1 ** 10while (error ** 2 > tolerance) {root = (min + max) / 2.0error = root ** 2 - 2.0if (error > 0.0) {max = root} else {min = root}}println("2 的平方根约等于:${root}")
}

输出:

2 的平方根约等于:1.414215

do-while表达式

基本形式为:

do {循环体
} while (条件)

计算1~100 之间所有整数的和

main(){ // 1~100 之间所有整数的和var sum = 0;var j = 1;do{sum += j;j++;} while( j <= 100)println("${sum}")
}

输出:

5050

break、continue

循环中的 break 和 continue 用法与 C 语言和 Js 语言一样。break 用于终止当前循环表达式的执行、转去执行循环表达式之后的代码,continue 用于提前结束本轮循环、进入下一轮循环。break 与 continue 表达式的类型都是 Nothing。

函数

Javscript的函数关键词是function,但是仓颉使用关键字 func 来表示函数定义的开始,func 之后依次是函数名、参数列表、可选的函数返回值类型、函数体。
案例:

func add(a: Int64, b: Int64):Int64 {return a + b;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com