# Y++ 基础语法说明
本文说明 D2D 项目中最常用的 Y++ 基础语法:变量、常量、数据类型、类型转换、运算符、数组、函数、作用域、条件和循环。支持库命令、窗口组件、`.yt`、`.ypi`、`.ypp` 的专门写法请继续查看同目录对应文档。
## 1. 源文件与代码结构
常用文件:
| 文件 | 用途 |
|---|---|
| `source/main.yc` | 窗口事件和主要业务代码 |
| `source/globals.yc` | 全工程共享变量,项目自动引用 |
| `source/constants.yc` | 全工程共享常量,项目自动引用 |
| `source/结构体文件/*.yt` | 自定义数据类型和结构体 |
| `source/类文件/*.ypp` | 自写类、属性、方法和继承 |
| `source/API声明/*.ypi` | DLL、Windows API 和第三方 C 接口声明 |
语句通常一行一条;代码块使用英文半角 `{` 和 `}`:
```yc
函数 演示() {
整数 数量 = 10
输出(数量)
}
```
错误写法:
```yc
// 错误:使用中文全角括号和花括号可能造成解析失败
函数 演示(整数 数量){
输出(数量)
}
```
应使用 IDE 自动转换后的英文半角标点。
## 2. 标识符与注释
变量、函数、类型、类和方法可使用中文名、英文字母、数字及下划线,但名称不能以数字开头,也不能与关键字冲突。
```yc
整数 用户数量 = 0
文本 user_name = "张三"
逻辑 已登录 = 假
```
单行注释:
```yc
// 这是一行注释
整数 次数 = 3 // 行尾注释
```
多行注释:
```yc
/*
这里是多行说明。
可用于暂时屏蔽多行代码。
*/
```
错误写法:
```yc
整数 2号用户 = 0 // 错误:数字开头
整数 如果 = 1 // 错误:使用关键字作为名称
```
## 3. 变量定义
基本格式:
```text
类型 变量名
类型 变量名 = 初始值
```
常见变量:
```yc
整数 年龄 = 18
短整数 状态码 = 200
长整数 文件大小 = 4294967296
小数 温度 = 36.5
单浮点 比例 = 0.75
双浮点 金额 = 1234.56
文本 姓名 = "张三"
逻辑 已完成 = 假
字节 一个字节 = 65
字节集 文件数据 = 创建字节集(1024)
通用 任意值 = "开始是文本"
```
先声明后赋值:
```yc
整数 总数
总数 = 10
总数 = 总数 + 5
```
一次只声明一个名称,最利于补全、错误定位和 AI 生成:
```yc
整数 左 = 10
整数 上 = 20
整数 宽 = 800
整数 高 = 600
```
错误写法:
```yc
年龄 整数 = 18 // 不推荐:统一使用“类型 名称”
整数 = 18 // 错误:缺少变量名
整数 年龄 = "十八" // 错误:文本不能直接赋给整数
```
需要把文本年龄变成整数时显式转换:
```yc
整数 年龄 = 到整数("18")
```
## 4. 基本数据类型怎么选择
| 类型 | 常见用途 | 示例 |
|---|---|---|
| `整数` | 计数、索引、状态码 | `整数 行 = 0` |
| `短整数` | 明确需要较小整数的原生接口 | `短整数 端口片段 = 80` |
| `长整数` | 文件大小、时间戳、句柄、地址 | `长整数 句柄 = 0` |
| `小数` / `双浮点` | 金额、坐标、测量值 | `小数 单价 = 9.9` |
| `单浮点` | 第三方接口明确要求 float | `单浮点 透明度 = 0.5` |
| `文本` | Unicode 字符串 | `文本 标题 = "主页"` |
| `逻辑` | 真/假状态 | `逻辑 运行中 = 真` |
| `字节` | 单个 0~255 数据 | `字节 标记 = 255` |
| `字节集` | 文件、图片、网络二进制 | `字节集 图片 = 读文件(路径)` |
| `通用` | 类型不固定的数据 | `通用 值 = 123` |
能确定类型时优先使用明确类型。`通用` 适合动态数据,但会降低类型检查和成员补全的准确性。
## 5. 文本与转义
文本使用英文双引号:
```yc
文本 标题 = "Y++ IDE"
文本 路径 = "D:\\data\\config.json"
文本 换行内容 = "第一行\n第二行"
文本 制表内容 = "名称\t数量"
文本 引号内容 = "他说:\"你好\""
```
Windows 路径也可使用 `/`,可减少转义:
```yc
文本 路径 = "D:/data/config.json"
```
拼接不同类型时显式转换:
```yc
文本 姓名 = "张三"
整数 年龄 = 18
文本 简介 = 姓名 + ",年龄=" + 到文本(年龄)
```
错误写法:
```yc
文本 路径 = "D:\data\new" // 错误风险:\n 会被解释成换行
文本 简介 = "年龄=" + 年龄 // 不要依赖隐式转换
```
## 6. 类型转换与类型判断
常用转换命令:
```yc
整数 数量 = 到整数("123")
小数 单价 = 到小数("19.95")
文本 数量文本 = 到文本(数量)
逻辑 开关 = 到逻辑(1)
字节集 数据 = 到字节集("你好")
文本 当前类型 = 取类型(数量)
```
组合示例:读取文本框并校验:
```yc
函数 保存按钮.单击(整数 X, 整数 Y) {
文本 原始年龄 = 年龄输入框.标题
整数 年龄 = 到整数(原始年龄)
如果 (年龄 <= 0) {
输出("年龄必须是正整数")
返回
}
输出("保存年龄:" + 到文本(年龄))
}
```
小数转整数会去掉小数部分:
```yc
整数 a = 到整数(3.9) // 结果为 3
整数 b = 到整数(-3.9) // 向零截断
```
错误写法:
```yc
整数 数量 = "123" // 错误:没有转换
整数 数量 = 到文本(123) // 错误:转换结果仍是文本
小数 金额 = 到整数("9.9") // 结果先被截断,不符合金额用途
```
正确写法:
```yc
整数 数量 = 到整数("123")
小数 金额 = 到小数("9.9")
```
## 7. 常量
局部常量:
```yc
函数 计算() {
常量 整数 每页数量 = 50
输出(每页数量)
}
```
`source/constants.yc` 中的项目常量:
```yc
全局常量 文本 程序版本 = "2.6.0"
全局常量 整数 默认端口 = 8080
全局常量 逻辑 启用日志 = 真
```
其它文件使用项目全局常量:
```yc
输出("版本=" + #程序版本)
整数 端口 = #默认端口
```
错误写法:
```yc
#默认端口 = 9000 // 错误:常量不能重新赋值
输出(默认端口) // 跨文件项目常量漏写 #
```
## 8. 局部变量、全局变量和作用域
函数或方法内部定义的是局部变量,只在当前代码块所属函数或方法中使用:
```yc
函数 计算总价(整数 数量, 小数 单价) 小数 {
小数 总价 = 数量 * 单价
返回(总价)
}
```
`source/globals.yc` 中定义全局变量:
```yc
整数 登录次数 = 0
逻辑 程序运行中 = 真
文本 当前用户 = ""
学生 学生列表[]
```
其它 `.yc`、`.ypp` 文件可直接使用这些全局变量。
方法参数也属于当前方法的局部变量:
```ypp
类 日志器 {
方法 写入(文本 内容, 整数 级别) {
// 内容、级别在本方法内应参与代码补全
输出("[" + 到文本(级别) + "] " + 内容)
}
}
```
错误写法:
```yc
函数 A() {
整数 临时值 = 10
}
函数 B() {
输出(临时值) // 错误:A 的局部变量在 B 中不可见
}
```
## 9. 赋值与运算符
```yc
整数 a = 10
整数 b = 3
整数 和 = a + b
整数 差 = a - b
整数 积 = a * b
整数 商 = a / b
整数 余数 = a % b
a += 2
a -= 1
a *= 3
a /= 2
a++
b--
```
比较与逻辑:
```yc
逻辑 相等 = (a == b)
逻辑 不等 = (a != b)
逻辑 大于 = (a > b)
逻辑 范围内 = (a >= 1 && a <= 100)
逻辑 任一成立 = (a == 0 || b == 0)
逻辑 未完成 = !已完成
```
不要把比较 `==` 写成赋值 `=`:
```yc
如果 (状态 = 1) { } // 错误:条件中误用了赋值
如果 (状态 == 1) { } // 正确:比较是否相等
```
复杂表达式用括号明确顺序:
```yc
小数 平均值 = (总分 + 加分) / 人数
逻辑 可提交 = 已登录 && (数量 > 0) && (金额 <= 余额)
```
## 10. 一维数组
强类型数组:
```yc
整数 分数[] = [90, 85, 100]
文本 姓名[] = ["张三", "李四"]
学生 学生列表[]
```
固定初始容量或长度提示:
```yc
多线程 dxc[10] = []
```
访问下标从 `0` 开始:
```yc
输出(分数[0])
分数[1] = 88
数组添加(姓名, "王五")
整数 人数 = 数组长度(姓名)
```
遍历:
```yc
整数 i = 0
当 (i < 数组长度(姓名)) {
输出(到文本(i) + ":" + 姓名[i])
i++
}
```
错误写法:
```yc
输出(姓名[2]) // 如果当前只有两个元素,下标越界
姓名[0] = 123 // 错误:文本数组元素不能直接放整数
```
## 11. 二维、三维及嵌套数组
```yc
整数 表格[][] = [[1, 2], [3, 4]]
输出(表格[0][1])
文本 立方体[][][] = [
[["A", "B"], ["C", "D"]]
]
输出(立方体[0][1][0])
```
自定义类型数组可继续访问成员:
```yc
学校 我校
输出(我校.班级列表[0].成员[0].姓名)
输出(我校.班级列表[0].成员[0].家庭住址.门牌坐标.X)
```
类型数组元素里包含类对象时也可继续调用方法:
```yc
多线程 dxc[10] = []
dxc[0].主OL.我是ola第一个方法("任务一")
```
这类写法要求每一层都有明确类型:`dxc` 是 `多线程[]`、`主OL` 是 `ola`、目标方法属于 `ola`。若中间一层声明成 `通用`,IDE 无法可靠推出后续成员。
## 12. 条件语句
```yc
如果 (分数 >= 90) {
输出("优秀")
} 否则如果 (分数 >= 60) {
输出("及格")
} 否则 {
输出("不及格")
}
```
嵌套条件:
```yc
如果 (已登录) {
如果 (权限级别 >= 10) {
输出("管理员")
} 否则 {
输出("普通用户")
}
}
```
错误写法:
```yc
如果 分数 >= 60 { // 错误:条件缺少括号
输出("及格")
}
```
## 13. 循环、跳出和继续
`当` 循环:
```yc
整数 i = 0
当 (i < 10) {
i++
如果 (i == 3) {
继续
}
如果 (i > 8) {
跳出
}
输出(i)
}
```
循环必须保证条件最终会改变:
```yc
整数 i = 0
当 (i < 10) {
输出(i)
// 错误:漏写 i++,将形成无限循环
}
```
## 14. 函数定义、参数和返回值
无参数、无返回值:
```yc
函数 显示欢迎() {
输出("欢迎使用 Y++")
}
显示欢迎()
```
带参数:
```yc
函数 显示用户(文本 姓名, 整数 年龄) {
输出(姓名 + "," + 到文本(年龄) + "岁")
}
显示用户("张三", 18)
```
带返回值:
```yc
函数 计算面积(整数 宽, 整数 高) 整数 {
返回(宽 * 高)
}
整数 面积 = 计算面积(800, 600)
```
提前返回:
```yc
函数 保存(文本 路径) 逻辑 {
如果 (路径 == "") {
输出("路径不能为空")
返回(假)
}
写文件(路径, "内容")
返回(真)
}
```
错误写法:
```yc
函数 相加(整数 a, 整数 b) 整数 {
输出(a + b)
} // 错误:声明返回整数但没有返回值
相加("1", "2") // 错误:参数类型不匹配
```
## 15. 窗口事件中的变量
事件参数由组件事件签名决定:
```yc
函数 按钮1.单击(整数 X, 整数 Y) {
文本 坐标 = 到文本(X) + "," + 到文本(Y)
输出(坐标)
}
```
不要自行复制另一种组件的参数签名,应从设计器事件面板生成:
```yc
// 错误示意:当前组件的单击事件可能并不提供“行、列”
函数 按钮1.单击(整数 行, 整数 列, 文本 内容) {
}
```
## 16. 自定义数据类型变量
`.yt`:
```yt
地址 {
文本 省
文本 市
}
学生 {
文本 姓名
整数 年龄
地址 家庭住址
}
```
`.yc`:
```yc
学生 张三
张三.姓名 = "张三"
张三.年龄 = 18
张三.家庭住址.省 = "广东省"
张三.家庭住址.市 = "深圳市"
输出(张三.家庭住址.市)
```
错误写法:
```yc
张三.家庭地址.市 = "深圳市" // 错误:声明的成员叫“家庭住址”
```
## 17. 自写类变量和方法参数
`.ypp`:
```ypp
类 订单服务 {
文本 当前用户 = ""
方法 设置用户(文本 用户名) {
当前用户 = 用户名
}
方法 计算金额(整数 数量, 小数 单价) 小数 {
小数 金额 = 数量 * 单价
返回(金额)
}
}
```
`.yc`:
```yc
订单服务 服务
服务.设置用户("张三")
小数 金额 = 服务.计算金额(3, 19.9)
```
方法形参 `用户名`、`数量`、`单价` 只在各自方法体内有效,并应像局部变量一样参与代码补全。
## 18. 通用类型的使用边界
```yc
通用 值 = 123
输出(取类型(值))
值 = "文本"
输出(取类型(值))
```
不要用 `通用` 代替本来明确的自定义类型:
```yc
通用 学生值
// 学生值.姓名 // IDE 无法保证成员类型和补全
学生 学生值2
学生值2.姓名 = "张三"
```
## 19. 常见错误对照
| 错误写法 | 原因 | 正确写法 |
|---|---|---|
| `整数 = 1` | 缺少变量名 | `整数 数量 = 1` |
| `整数 数量 = "1"` | 类型不同 | `整数 数量 = 到整数("1")` |
| `如果 (a = 1)` | 把赋值写成比较 | `如果 (a == 1)` |
| `输出(未声明变量)` | 名称不在作用域 | 先声明或放入 `globals.yc` |
| `数组[数组长度(数组)]` | 下标越界 | 最后一个下标是长度减一 |
| `#常量 = 新值` | 常量不可修改 | 改用全局变量 |
| `对象.不存在成员` | 名称或类型链错误 | 按 `.yt`/`.ypp` 声明逐层访问 |
| `类名 对象(参数)` | 当前声明语法不接收该写法 | 先 `类名 对象`,再调用初始化方法 |
| `用户 a = new 用户()` | 混入其它语言语法 | `用户 a` |
| 方法参数在方法外使用 | 已离开参数作用域 | 传给其它函数或保存到类属性 |
## 20. 综合示例
`source/types/订单.yt`:
```yt
订单项 {
文本 商品名
整数 数量
小数 单价
}
订单数据 {
文本 编号
订单项 项目[]
}
```
`source/classes/订单计算器.ypp`:
```ypp
类 订单计算器 {
方法 计算总额(订单数据 订单) 小数 {
小数 总额 = 0
整数 i = 0
当 (i < 数组长度(订单.项目)) {
总额 += 订单.项目[i].数量 * 订单.项目[i].单价
i++
}
返回(总额)
}
}
```
`source/main.yc`:
```yc
函数 计算按钮.单击(整数 X, 整数 Y) {
订单数据 订单
订单.编号 = "NO-1001"
订单项 商品
商品.商品名 = "键盘"
商品.数量 = 到整数(数量输入框.标题)
商品.单价 = 到小数(单价输入框.标题)
数组添加(订单.项目, 商品)
订单计算器 计算器
小数 总额 = 计算器.计算总额(订单)
结果标签.标题 = "订单" + 订单.编号 + ",总额=" + 到文本(总额)
}
```
这个示例同时使用了事件参数、局部变量、文本转整数、小数转换、自定义数据类型、类型数组、自写类方法、循环和返回值。
评论