当前位置: 首页 > news >正文

仓颉编程语言的基本概念:标识符、变量、注释

仓颉编程语言的基本概念:标识符、变量、注释

现在介绍仓颉编程语言的基本概念

标识符

在仓颉编程语言中,开发者可以给一些程序元素命名,这些名字被称为“标识符”。

在仓颉语言中,标识符是用户定义的名称,用于变量、函数、类等实体的标记。良好的标识符命名规则是编写可维护代码的基础。

标识符区分大小写(Variable 和 variable 是不同的标识符)。

仓颉编程语言的标识符分为普通标识符和原始标识符两类:

①普通标识符不能和仓颉关键字相同,由 XID_Start字符(包含中文和英文等字符)或_开头开头,后接任意长度的 XID_Continue 字符(包含中文、英文和阿拉伯数字等字符)。合法的标识符

userName

_age

合计

core123

非法的标识符(会导致编译错误)

123user  // 不能以数字开头

ab&c  //其中&不是 XID_Continue 字符

while  // while 是仓颉关键字,普通标识符不能直接使用仓颉关键字

②原始标识符是在普通标识符或仓颉关键字的首尾加上一对反引号,主要用于将仓颉关键字作为标识符的场景。例如,以下每行字符串都是合法的原始标识符:

`abc`

`_abc`

`if`

`while`

以下每行字符串,由于反引号内的部分是不合法的普通标识符,所以它们整体也是不合法的原始标识符:

`ab&c`

`3abc`

变量

仓颉编程语言作为一种静态类型(statically typed)语言,要求每个变量的类型必须在编译时确定。

根据是否可进行修改,可将变量分为 3 类:不可变变量(一旦初始化,值不可改变)、可变变量(值可以改变)、const 变量(必须编译期初始化,不可修改)。

变量定义的具体形式为:

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

可变性修饰符关键字let/var/const说明:

    let用于定义不可变变量,let 变量一旦初始化就不能再改变。

    var用于定义可变变量。

const用于定义 const 变量。

通俗地说:

一句话:

let = 上锁的盒子,放一次东西后永远不能再换;

var = 普通盒子,随时可以把里面的东西拿出来再放新的;

const = 出厂时就焊死、连盒子带内容一起封装的常量(不可省略初始化表达式)。

【其它常用的修饰符,还有:

  •  可见性修饰符:private 与 public 等,影响全局变量和成员变量的可引用范围。https://cangjie-lang.cn/docs?url=%2F0.53.18%2Fuser_manual%2Fsource_zh_cn%2Fpackage%2Ftoplevel_access.html

  •  静态性修饰符:static,影响成员变量(写在class / struct / interface / enum内部 的变量)的存储和引用方式。

初学者先不必深究,在此不介绍了。】

变量名应是一个合法的仓颉标识符。

变量类型指定了变量所持有数据的类型。当初始值具有明确类型时,可以省略变量类型标注,此时编译器可以自动推断出变量类型。

初始值是一个仓颉表达式,用于初始化变量,如果标注了变量类型,需要保证初始值类型和变量类型一致。在定义全局变量或静态成员变量时,必须指定初始值。在定义局部变量或实例成员变量时,可以省略初始值,但需要标注变量类型,同时要在此变量被引用前完成初始化,否则编译会报错。

示例

main() {let a: Int64var b: Int64 = 14const c: Int64 = 30 let pi: Float64 = 3.14a = 12  // 使用let修饰的变量只能赋值一次,即只能初始化一次b = 20//pi = 3.14159  //错误,无法对不可变值进行赋值println("a = ${a}, b = ${b}, c = ${c}")  //a = 12, b = 20, c = 30println("pi = ${pi}") // pi = 3.140000
}

值类型和引用类型变量

从编译器实现层面看,任何变量总会关联一个值(一般是通过内存地址/寄存器关联),只是在使用时,对有些变量,将直接取用这个值本身,这被称为值类型变量;而对另一些变量,将这个值作为索引、取用这个索引指示的数据,这被称为引用类型变量

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

在使用值类型变量和引用类型变量时,会存在一些行为差异,以下几点值得注意:

1.在给值类型变量赋值时,一般会产生拷贝操作,且原来绑定的数据/存储空间会被覆盖。在给引用类型变量赋值时,只是改变了引用关系,原来绑定的数据/存储空间不会被覆盖。

2.用 let 定义的变量,要求变量被初始化后都不能再赋值。对于引用类型,这只是限定了引用关系不可改变,但是所引用的数据是可以被修改的。

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

通俗解释:

值类型和引用类型的核心区别:本质是变量与数据的关联方式不同(独占 vs 共享),这导致了它们在赋值、修改等操作上的行为差异。下面结合具体示例说明:

值类型:变量直接 “持有” 数据本身,数据是 “独占” 的。就像你手里拿着一张纸质照片,给别人时需要复印一份,你改自己的照片不会影响别人的。

引用类型:变量不直接持有数据,而是持有数据的 “地址”(引用),数据可以被多个变量 “共享”。就像你和朋友都知道同一张电子照片的存储路径,你修改这张照片,朋友看到的也会变。

示例说明

1.值类型:拷贝整份数据

struct Point {            // 值类型var x: Int64var y: Int64public init(x: Int64, y: Int64) {this.x = xthis.y = y}
}main() {var a = Point(1, 2)   // a 独占一块栈内存var b = a             // 整份数据拷贝!b 拥有独立副本b.x = 99              // 只改 b 的副本println("a.x = ${a.x}, b.x = ${b.x}")   // a.x = 1, b.x = 99
}

2. 引用类型:赋值只复制“地址”

class Counter {           // 引用类型public var value: Int64 = 0
}main() {var c1 = Counter()    // c1 保存的是“对象地址”var c2 = c1           // 只复制地址,两个变量指向同一块堆内存c2.value = 42println("c1.value = ${c1.value}, c2.value = ${c2.value}")  // 都是 42
}

3. let 与可变性:值类型 vs 引用类型

// 值类型
struct Size { var w: Int64 var h: Int64public init(w: Int64, h: Int64) {this.w = wthis.h = h}}   // 引用类型
class Box { var width: Int64 = 0 
}        main() {let s = Size(10, 20)    // 值类型 + let → 整个值不可改println("s.w = ${s.w}, s.h = ${s.h}") // s.w = 10, s.h = 20//s.w = 30             // ❌ 编译错误let b = Box()           // 引用类型 + let → 引用不可改,但对象内容可改b.width = 100           // ✅ 合法:只是改堆上的对象,引用关系没变println(b.width)        // 100
}

4. Array 的拷贝行为

main() {var a: Array<Int64> = [1, 2, 3]   // Array 是引用类型var b = a                         // 只复制引用b[0] = 99println("a[0] = ${a[0]}, b[0] = ${b[0]}")  // 都是 99
}

不可变类型和 可变类型

不可变:值一旦设定,内存里的数据永远不变,修改变量=创建新值,保证数据安全性(尤其多线程场景)。

可变:内存里的原数据可以直接被修改(无需频繁创建新对象)。

例如:

main() {// ---------------- 不可变:String ----------------let s1 = "hello"  // let用于定义不可变变量println(" s1 = ${s1}")      var sA = "Hi"  // var用于定义可变变量println(" sA = ${sA}") sA = s1 + ", world"  //修改变量=创建新值println(" sA = ${sA}") // ---------------- 可变:Array<Int64> ------------let arr1: Array<Int64>  = ([1, 2, 3])let arr2 = arr1          // arr2 与 arr1 指向同一块内存println(" arr2 = ${arr2}")     arr1[0] = 10;  // 索引0的元素从1变为10println(" arr1 = ${arr1}")  
}

输出如下:

 s1 = hello
 sA = Hi
 sA = hello, world
 arr2 = [1, 2, 3] 
 arr1 = [10, 2, 3]

注释

注释内容不影响程序的编译和运行,华为仓颉编程语言的注释有:

1.单行注释

语法:以 // 开头,直到行尾的内容均为注释。

2. 多行注释(块注释)

语法:以 /* 开头,以 */ 结尾,中间的内容均为注释(可跨多行)。多行注释常见的行前加 *”的写法,纯粹是为了让注释块在视觉上对齐,方便阅读,不是语法要求。

示例:

/* 
这是多行注释
多行注释可以写多行
* 有人喜欢在多行注释行前加 *的写法,不是语法要求
*/
main() {   let a: Bool = true  // 声明一个布尔类型(Bool)变量a并赋值为trueif (a) { println(a)  // 输出:true}
}

http://www.dtcms.com/a/316884.html

相关文章:

  • 信息安全概述--实验总结
  • mcu中的RC振荡器(Resistor-Capacitor Oscillator)
  • 企业高性能web服务器
  • 【docker】UnionFS联合操作系统
  • 2025年渗透测试面试题总结-02(题目+回答)
  • 一种红外遥控RGB灯带控制器-最低价MCU
  • Redis类型之String
  • linux-单用户模式、营救模式
  • 高阶 RAG :技术体系串联与实际落地指南​
  • RHCA03--硬件监控及内核模块调优
  • 【Spring Cloud】-- RestTeplate实现远程调用
  • Java开发时出现的问题---并发与资源管理深层问题
  • 嵌入式开发学习———Linux环境下IO进程线程学习(四)
  • 《嵌入式数据结构笔记(三):数据结构基础与双向链表》
  • 应急响应排查思路
  • MLIR Bufferization
  • JWT 签名验证失败:Java 与 PHP 互操作问题解决方案
  • OpenHarmony 5.0 Settings中wifi删除密码立刻去输入密码连接,连接不上
  • 性能测试终极指南:从指标到实战
  • 自动驾驶中的传感器技术24——Camera(15)
  • Mybatis的应用及部分特性
  • 机器学习——集成学习(Ensemble Learning):随机森林(Random Forest),AdaBoost、Gradient Boosting,Stacking
  • 企业级Redis Cluster部署详解及演练
  • 森赛睿科技成为机器视觉产业联盟会员单位
  • 解决cv::dilate处理后的图像边缘像素出现异常值的问题
  • 结构化设计工具与技术详解
  • Spring 的优势
  • 内部排序算法总结(考研向)
  • 从递归到动态规划-解码方法Ⅱ
  • 软件测试面试如何避坑呢?