返回列表

帖子详情

经验分享

Y++ 自定义数据类型语法说明

作者:管理员发布:2026-08-11 01:49:19浏览:0
# Y++ 自定义数据类型语法说明

自定义数据类型使用 `.yt` 文件,适合保存一组字段、嵌套数据和与 DLL 对应的结构体布局。`.yt` 只定义数据,不写事件、执行语句、方法或继承。

## 1. 文件和基本定义

文件放在项目 `source/` 或其子目录:

```text
source/types/学生.yt
```

简写语法:

```yt
学生 {
    整数 学号 = 0
    文本 姓名
    逻辑 启用 = 真
}
```

结构体写法:

```yt
结构体 矩形 {
    整数 左 = 0
    整数 上 = 0
    整数 右 = 0
    整数 下 = 0
}
```

两种写法都表示纯字段类型。加入项目后在 `.yc``.ypp` 和其它 `.yt` 中直接使用,无需 `#include`

## 2. 字段类型和默认值

```yt
任务信息 {
    整数 编号 = 0
    长整数 文件大小 = 0
    小数 进度 = 0
    文本 标题 = ""
    逻辑 已完成 = 假
    字节集 原始数据
}
```

基础字段可给默认值。字段名在同一类型中不能重复。

使用:

```yc
任务信息 任务
任务.编号 = 1001
任务.标题 = "导入数据"
任务.进度 = 0.5
输出(任务.标题)
```

## 3. 嵌套自定义类型

```yt
坐标 {
    小数 X = 0
    小数 Y = 0
}

地址 {
    文本 省
    文本 市
    文本 街道
    坐标 门牌坐标
}

人员 {
    文本 姓名
    地址 家庭住址
}
```

逐层赋值和读取:

```yc
人员 张三
张三.姓名 = "张三"
张三.家庭住址.省 = "广东"
张三.家庭住址.市 = "深圳"
张三.家庭住址.门牌坐标.X = 113.9
张三.家庭住址.门牌坐标.Y = 22.5

输出(张三.家庭住址.市)
输出(张三.家庭住址.门牌坐标.X)
```

也可以先构造内层对象再整体赋值:

```yc
地址 新地址
新地址.省 = "浙江"
新地址.市 = "杭州"

人员 李四
李四.姓名 = "李四"
李四.家庭住址 = 新地址
```

## 4. 动态数组和限长数组

类型数组:

```yc
人员 成员[] = []

人员 张三
张三.姓名 = "张三"
数组添加(成员, 张三)

人员 李四
李四.姓名 = "李四"
数组添加(成员, 李四)

输出(成员[0].姓名)
输出(成员[1].姓名)
```

限制最大数量:

```yc
人员 成员[40] = []
```

预分配元素:

```yc
人员 成员[40]
成员[0].姓名 = "张三"
```

下标从 0 开始。访问前应确认数组长度:

```yc
如果 (数组长度(成员) > 0) {
    输出(成员[0].姓名)
}
```

## 5. 类型内部的数组字段

```yt
学生 {
    文本 姓名
    整数 成绩[] = []
}

班级 {
    文本 名称
    学生 成员[] = []
}
```

```yc
学生 张三
张三.姓名 = "张三"
数组添加(张三.成绩, 96)
数组添加(张三.成绩, 88)

班级 一班
一班.名称 = "软件一班"
数组添加(一班.成员, 张三)

输出(一班.成员[0].姓名)
输出(一班.成员[0].成绩[1])
```

## 6. 多层数组嵌套完整示例

```yt
坐标 {
    小数 X = 0
    小数 Y = 0
}

家庭地址 {
    文本 市
    坐标 门牌坐标
}

学生 {
    文本 姓名
    家庭地址 家庭住址
}

班级 {
    学生 成员[] = []
}

学校 {
    文本 校名
    班级 班级列表[] = []
}
```

```yc
函数 创建学校() 学校 {
    学生 新学生
    新学生.姓名 = "张三"
    新学生.家庭住址.市 = "深圳"
    新学生.家庭住址.门牌坐标.X = 100.5

    班级 新班级
    数组添加(新班级.成员, 新学生)

    学校 我校
    我校.校名 = "示例学校"
    数组添加(我校.班级列表, 新班级)
    返回(我校)
}

函数 主窗口.创建完毕() {
    学校 我校 = 创建学校()
    输出(我校.班级列表[0].成员[0].姓名)
    输出(我校.班级列表[0].成员[0].家庭住址.市)
    输出(我校.班级列表[0].成员[0].家庭住址.门牌坐标.X)
}
```

## 7. 按添加时的变量名访问

通过 `数组添加(数组, 变量名)` 加入的对象可按下标访问;支持命名访问的数组也可写:

```yc
学生 学生列表[] = []
学生 张三
张三.姓名 = "张三"
数组添加(学生列表, 张三)

输出(学生列表[0].姓名)
输出(学生列表.张三.姓名)
```

动态下标适合循环,命名访问适合固定配置成员。

## 8. 作为函数参数

值参数:

```yc
函数 打印学生(学生 s) {
    输出(s.姓名)
}

学生 张三
张三.姓名 = "张三"
打印学生(张三)
```

多个自定义类型参数:

```yc
函数 是否同城(学生 a, 学生 b) 逻辑 {
    返回(a.家庭住址.市 == b.家庭住址.市)
}
```

## 9. 作为函数返回值

```yc
函数 新建学生(文本 姓名, 文本 城市) 学生 {
    学生 s
    s.姓名 = 姓名
    s.家庭住址.市 = 城市
    返回(s)
}

学生 新同学 = 新建学生("王五", "广州")
输出(新同学.家庭住址.市)
```

修改后返回并回写:

```yc
函数 修改城市(学生 s, 文本 城市) 学生 {
    s.家庭住址.市 = 城市
    返回(s)
}

新同学 = 修改城市(新同学, "佛山")
```

## 10. 全局自定义类型变量

`source/globals.yc`

```yc
学校 当前学校
学生 在线学生[] = []
```

其它文件直接使用:

```yc
函数 主窗口.创建完毕() {
    当前学校.校名 = "第一中学"
    输出(当前学校.校名)
}
```

不要在多个文件重复声明同名全局对象。

## 11. 与自写类组合

`.yt` 负责数据,`.ypp` 负责行为:

```ypp
类 学生服务 {
    方法 修改姓名(学生 s, 文本 新姓名) 学生 {
        s.姓名 = 新姓名
        返回(s)
    }

    方法 显示(学生 s) {
        输出(s.姓名 + " / " + s.家庭住址.市)
    }
}
```

```yc
学生服务 服务
学生 s = 新建学生("赵六", "东莞")
s = 服务.修改姓名(s, "赵小六")
服务.显示(s)
```

## 12. 与 `.ypi` API 组合

结构体字段顺序、类型宽度必须与第三方 DLL 头文件一致:

```yt
结构体 原生矩形 {
    整数 left
    整数 top
    整数 right
    整数 bottom
}
```

```ypi
DLL("user32.dll", "stdcall")
逻辑 GetWindowRect(长整数 窗口句柄, 原生矩形 结果) 读取原生窗口矩形
```

```yc
原生矩形 r
如果 (读取原生窗口矩形(窗口句柄, r)) {
    输出("宽=" + 到文本(r.right - r.left))
}
```

## 13. 错误写法与正确写法

### 错误:在 `.yc` 中临时定义类型

```yc
// 错误
学生 {
    文本 姓名
}
```

正确做法:放到 `.yt` 文件。

### 错误:在 `.yt` 中写方法

```yt
// 错误
学生 {
    文本 姓名
    方法 打印() { }
}
```

正确做法:数据放 `.yt`,方法放 `.ypp` 类。

### 错误:类型和变量顺序写反

```yc
// 错误
张三 学生

// 正确
学生 张三
```

### 错误:漏写数组下标

```yc
// 错误:成员是数组
我校.班级列表.成员.姓名

// 正确
我校.班级列表[0].成员[0].姓名
```

### 错误:数组越界

```yc
学生 成员[] = []
// 错误:数组仍为空
输出(成员[0].姓名)
```

正确做法:先 `数组添加`,或检查 `数组长度`

### 错误:字段不存在

```yc
// 学生类型未定义“年龄”
张三.年龄 = 20
```

正确做法:在 `.yt` 增加字段并保存,或使用真实字段名。

### 错误:把自定义类型当类方法调用

```yc
// 错误:纯 .yt 类型没有方法
张三.保存()
```

正确做法:定义 `学生服务` 类并写 `服务.保存(张三)`

### 错误:原生结构体字段宽度错误

```yt
// x64 指针字段错误使用整数,地址可能被截断
结构体 原生数据 {
    整数 地址
}
```

正确做法:x64 地址、指针、句柄使用 `长整数`,并逐字段核对 DLL 文档。

### 错误:修改值参数后认为原对象一定变化

```yc
函数 改名(学生 s) {
    s.姓名 = "新名字"
}
```

稳妥写法是返回并回写:

```yc
函数 改名(学生 s) 学生 {
    s.姓名 = "新名字"
    返回(s)
}

张三 = 改名(张三)
```

## 14. 排查顺序

1. 确认 `.yt` 已出现在项目树并已保存。
2. 检查类型名、变量名、字段名有没有写反或拼错。
3. 点号链每遇到数组都先写 `[下标]`
4. 如果点号出现不相关成员,先检查链条前一段的类型是否可解析。
5. 原生 API 结构体逐字段核对顺序、宽度和 x86/x64 差异。


评论