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

仓颉编程语言青少年基础教程:程序基本结构和语言特点

仓颉编程语言青少年基础教程:程序基本结构和语言特点

仓颉编程语言是一种现代化的编程语言,设计注重简洁性、安全性和表达力。本文介绍其程序基本结构和语言特点。

程序基本结构

仓颉程序文件的扩展名为 .cj,这些程序和文件也被称为源代码和源文件。

如果要将仓颉程序编译为可执行文件,需要在顶层作用域中定义一个 main 函数作为程序入口,它可以没有参数,也可以有 Array<String> 类型的参数,它的返回值类型可以是整数类型或 Unit 类型。

☆ 没有参数、返回 Unit 的简单示例:

main() { // 不写返回类型,返回 Unitprintln("Hello, 仓颉!")
}

编译 & 运行输出:

Hello, 仓颉!

☆ 若为main 函数明确指定为整数类型(如Int64),按照编程惯例通常返回 0 表示程序正常结束,这种情况下若不写return 0,会导致编译错误(因为函数承诺返回整数但未履行)。简单示例:

main(): Int64{ println("hello")return 0
}

编译 & 运行输出:

Hello

☆ 接收命令行参数

如果需要获取程序启动时的命令行参数,可以声明和使用 Array<String> 类型参数。示例如下:

main(args: Array<String>): Int64 {println("收到参数个数: ${args.size}")   // 先打印真实长度// 从 0 开始打印所有实参for (i in 0 .. args.size) {println("参数 ${i} = ${args[i]}")}return 0 //习惯写上返回 0 表示正常结束
}

编译后测试:

对于新手而言,测试时需要注意路径问题。说明如下:

①在cmd中,用 cd /d 命令切换到cangjie\runtime\lib\windows_x86_64_llvm的路径,若已经将其放入环境变量path中,以后可以省略这一步。我这里的路径如下:

D:\cangjie-sdk-windows-x64-1.0.0\cangjie\runtime\lib\windows_x86_64_llvm

【cangjie\runtime\lib\windows_x86_64_llvm的路径,读者要根据自己的实际情况调整,否者,报找不到两个.dll文件:libsecurec.dll、libcangjie-runtime.dll 错误,无法继续执行代码。】

②再运行编译生成生成的可执行文件(.exe文件),带路径,如下

C:\Users\Wang\IDEProjects\test_3\target\release\bin\main.exe a b c

【我这里的编译生成的可执行文件名是main.exe ,扩展名“.exe”可以省略】

运行截图:

☆ 在仓颉程序的顶层作用域中,可以定义一系列的变量、函数和自定义类型(如 struct、class、enum 和 interface 等),其中的变量和函数分别被称为全局变量和全局函数。示例代码:

// 1. 全局变量
let welcome = "你好, 仓颉!"// 2. 全局函数(顶层作用域不需要 func 修饰符)
func add(a: Int64, b: Int64): Int64 {return a + b
}// 3. 自定义枚举类型
enum Color { Red | Green | Blue }// 4. 程序入口
main() {println(welcome)                       // 使用全局变量println("1 + 2 = ${add(1, 2)}")        // 调用全局函数let c = Color.Redlet name = match (c) {case Color.Red   => "Red"case Color.Green => "Green"case Color.Blue  => "Blue"}println("枚举值示例: ${name}")          // 使用自定义枚举类型
}

编译 & 运行输出:

你好, 仓颉!
1 + 2 = 3      
枚举值示例: Red

仓颉编程语言特点

多范式编程:函数式 + 面向对象 + 命令式。

支持函数式编程,具备高阶函数、代数数据类型、模式匹配和泛型等特性;也支持面向对象编程,拥有封装、接口、继承和多态等机制;还支持命令式编程,有值类型、全局函数等。开发者可根据具体场景灵活选择或混合使用不同编程范式。

简单地说

  •  函数式:描述“做什么”。

  •  面向对象:把数据和方法打包。

  •  命令式:一步步告诉电脑“怎么做”,强调“步骤 + 状态变化”。

       ••  面向过程(procedural) 是命令式的一个子集,额外强调“把步骤封装成过程/函数”来复用。

简单示例:同一道题(把一串数字平方后求和,输出结果:30)演示这些范式在仓颉里的写法:

(1) 函数式

main(): Int64 {let nums = [1, 2, 3, 4]var sum = 0for (x in nums.map { it => it * it }) {   // 先平方sum += x}println("函数式结果:${sum}")return 0
}

特点:

  • 使用高阶函数 map 进行数据转换
  • 使用 lambda 表达式 { it => it * it } 定义转换逻辑
  • 强调"做什么"(先平方,再求和)而不是"怎么做"
  • 虽然使用了可变变量 sum,但整体思路是函数式的

(2) 面向对象

class SquareSum {private let nums: Array<Int64>init(nums: Array<Int64>) {this.nums = nums}func compute(): Int64 {var s = 0for (n in nums) { s += n * n }return s}
}main(): Int64 {let obj = SquareSum([1, 2, 3, 4])println("面向对象结果:${obj.compute()}")return 0
}

特点:

  • 将数据 (nums) 和操作数据的方法 (compute) 封装在类中
  • 使用访问控制修饰符 private 实现数据隐藏
  • 通过创建对象实例来执行操作
  • 体现了"数据和方法打包"的面向对象核心思想

(3) 命令式

main(): Int64 {let nums = [1, 2, 3, 4]var sum = 0for (i in nums) {sum += i * i}println("命令式结果:${sum}")return 0
}

特点:

  • 明确指定执行步骤:初始化变量、循环遍历、累加计算
  • 使用可变状态 (sum 变量)
  • 关注"怎么做"的具体步骤
  • 代码直接、直观,但没有抽象和封装

(4) 面向过程

/* 1. 过程函数:平方和 */
func squareSum(nums: Array<Int64>): Int64 {var sum = 0for (n in nums) {sum += n * n        // 先平方再累加}return sum
}/* 2. 主过程:顺序调用 */
main(): Int64 {let nums = [1, 2, 3, 4]let result = squareSum(nums)   // 调用过程println("面向过程结果:${result}")return 0
}

特点:

  • 将算法步骤封装成过程/函数 (squareSum)
  • 通过函数调用组织代码逻辑
  • 强调代码复用和模块化
  • 是命令式编程的一种更结构化的形式

内存安全:自动垃圾回收 + 运行时下标 / 溢出检查。

内置自动内存管理机制,即垃圾回收机制,并且在运行时会进行数组下标越界和溢出检查,确保内存使用的安全性。

类型安全:仓颉编程语言是一种静态类型(statically typed)语言。同时,仓颉编程语言是一种强类型(strongly typed)语言。

  •  静态(static)类型:

变量、函数参数、返回值等在 编译阶段 就已确定类型,编译器会在写代码时就帮你揪出类型错误。

仓颉是静态类型语言,变量类型在编译时就固定,之后不能变。例如:

let age: Int = 25  // 这个age盒子只能装整数,装字符串会直接报错

如果后面你写 age = "hello",编译器会报错。

  •  强( strong)类型:

不同类型之间 不会自动隐式转换(例如 Int 不能直接当 Float 用,必须显式转换),从而避免运行时因隐式转换带来的隐患。

仓颉是强类型语言,不同类型之间不能直接混用,除非显式转换。例如

let a: Int = 5

let b: Float = 3.14

let c = a + b  // ❌ 报错!不能直接相加

// 正确做法:

let c = Float(a) + b  // ✅ 显式转换

仓颉中的类型

仓颉中的类型可分为两类:不可变类型(immutable type)和可变类型(mutable type)。其中,不可变类型包括数值类型(分为整数类型和浮点数类型(整数类型如Int32、Int64 UInt32、UInt64 ,浮点类型如Float32 、 Float64)、Rune 类型、Bool 类型、Unit 类型、Nothing 类型、String 类型、元组(Tuple)类型、Range 类型、函数(Function)类型、enum 类型;可变类型包括 Array 类型、VArray 类型、struct 类型、class 类型和 interface 类型。

不可变类型和可变类型的区别在于:不可变类型的值,其数据值一经初始化后就不会发生变化;可变类型的值,其数据值初始化后仍然有可以修改的方法。

不可变类型 vs 可变类型

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

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

例如:

main(): Int64 {// ---------------- 不可变: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}")  return 0
}

输出如下:

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

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

相关文章:

  • Day31 进程间通信(IPC)多线程目录扫描
  • mysql(自写)
  • 谈物质的运动与运动的物质
  • 基于立创・庐山派 K230CanMV 开发板的视觉引导舵机追踪系统技术分析
  • kafka(自写)
  • 【MYSQL】GET_LOCK使用方法简单解析
  • C++_静态多态、运行多态和模板多态
  • 下一代 AI 交互革命:自然语言对话之外,“意念控制” 离商用还有多远?
  • AWD相关知识
  • Scikit-learn Python机器学习 - 数据集介绍
  • 矿物类型分类实战:从数据预处理到多模型对比
  • 幻觉与模仿:深入剖析当前大语言模型为何未能跨越“理解”与“推理”的鸿沟
  • TuringComplete游戏攻略(2.1算数运算)
  • 基础的汇编指令
  • 如何快速了解项目管理基础
  • 【机器学习入门】4.1 聚类简介——从“物以类聚”看懂无监督分组的核心逻辑
  • destoon8.0使用post插入keyword热搜到表
  • 深入理解shared_ptr与循环引用问题
  • 超越传统SEO:用生成引擎优化(GEO)驱动下一轮增长
  • 【蓝桥杯 2024 省 Python B】缴纳过路费
  • Markdown 文件编辑基础教程
  • 基于YOLO8的垃圾识别检测系统(数据集+源码+文章)
  • 【开题答辩全过程】以 线上游戏商城为例,包含答辩的问题和答案
  • Java学习day_14之API(正则表达式)
  • 【LeetCode】大厂面试算法真题回忆(121) —— 经典屏保
  • 嵌入式Linux驱动开发:蜂鸣器驱动
  • 图解LLM(AI大模型)的工作原理
  • SRE命令行兵器谱之二:lsof - 解密“端口被占用”与“文件句柄泄漏”的终极侦探
  • 吴恩达机器学习作业九:kmeans聚类
  • php电子签名