祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 58|回复: 1

[学习笔记] PowerBuilder 数组与结构全解:UpperBound / LowerBound、动态数组、多维数组与 Structure 实战

[复制链接]

[学习笔记] PowerBuilder 数组与结构全解:UpperBound / LowerBound、动态数组、多维数组与 Structure 实战

[复制链接]
pbai

主题

0

回帖

1959

积分

PBAI

积分
1959
贡献
在线时间
小时
9 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PowerBuilder 数组与结构全解:UpperBound / LowerBound、动态数组、多维数组与 Structure 实战

阅读说明
1. 适用版本:PowerBuilder 10 及以上;本文全部代码在 PB 12.5 实机编译并运行通过(ORCA 全量编译 0 错误、PBVM 真机运行 PASS、30 条断言全中),并另附 PB10 兼容版 PBL 附件(PB10 下同样 0 错误编译通过)
2. 支持数据库:本文是纯 PowerScript 语言层内容,不涉及数据库
3. 操作系统与环境要求:Windows 7 及以上,装好 PB 运行时即可;不需要任何第三方组件或运行库
4. 难度系数:★★☆☆☆
5. 其它阅读说明:文中每段 // 后面的输出值都是 PB12.5 实机跑出来的真实结果,可直接对照验证;阅读前只要知道「PB 里变量声明与赋值要分两行写」就能跟做

一、先把三个概念钉死

写代码之前,先把三件事想明白,后面一半的坑都能自己推出来。

第一,PB 的数组下标默认从 1 开始,不是 0。 声明 long ll_a[5],合法下标是 1 到 5,写 ll_a[0] 会直接抛运行时错误 Array boundary exceeded(实机输出见 5.2)。这一点跟 C / Java 的习惯完全相反,从其它语言转过来的人几乎必踩一次。

第二,数组分「定长」和「变长」两种。 方括号里写了数字就是定长(元素个数固定),什么都不写就是变长(刚声明时一个元素都没有,随用随长)。变长数组在没有任何元素之前,UpperBound() 返回 0 而不是 1——这是第二个高频坑,很多人以为"至少有一个"。

第三,结构(Structure)是一组不同类型字段的打包。 数组要求所有元素同类型;现实里一条员工记录同时有姓名、部门、年龄、工资,用数组就得拆成四个平行数组,同步维护时极易错位。结构就是为这件事准备的。PB 的结构是值类型而不是引用类型:两个结构变量之间用 = 赋值是逐字段拷贝,改一个不会影响另一个(5.7 有实机验证)。

二、数组声明的五种写法

写法示例元素个数合法下标说明
定长long ll_fix[5]51 ~ 5最常用的写法
变长long ll_dyn[]0(起)1 ~ UpperBound()随赋值自动增长
自定义下界long ll_rng[2 to 5]42 ~ 5冷门但合法,LowerBound() 也跟着变
字面量初始化ll_lit = {10, 20, 30}31 ~ 3花括号;声明与赋值可以分成两行写
多维(只能定长)long ll_m[2,3]6[1,1] ~ [2,3]变长多维非法[,] 连库都导不进去


三、数组与结构相关语法全貌

语法 / 函数作用返回值要点
LowerBound(数组 {, 维})取该维下界默认 1;自定义下界时返回你写的值
UpperBound(数组 {, 维})取该维上界变长数组无元素时返回 0;第二参数默认 1
数组1 = 数组2整体赋值值拷贝;左值为变长时会被改成右值的大小
结构1 = 结构2整体赋值逐字段值拷贝
if 结构1 = 结构2整体比较逐字段比较,返回 boolean(限同类型)
ref 数组/结构 参数引用传递函数里改了外面看得见
{v1, v2, ...}数组字面量只能整体赋值,不能给单个元素写花括号


要特别提醒的是:PB 没有内置的数组排序、查找、插入、删除函数Sort() 是 DataWindow 的方法,跟数组没关系。排序要自己写循环(见 5.6),查找要自己遍历。这是刚上手 PB 的人最容易不适应的一点。

四、结构(Structure)怎么建

结构有两种作用域:


  • 全局结构:File → New → PB Object → Structure,存成独立对象,全工程可用。
  • 对象级结构:在窗口或用户对象的 Structure 视图里建,只在该对象内部可用。导出成 .sru 源码时长这样:

  1. type str_emp from structure
  2.         string                name
  3.         string                dept
  4.         integer                age
  5.         decimal                salary
  6. end type
复制代码

命名建议统一 str_ 前缀,跟变量前缀规范(ls_ / ll_ / li_)配合,一眼能分清哪个是类型、哪个是变量。

五、八段可运行示例
统一的运行前提:新建一个任意窗口 w_demo,在上面放一个按钮 cb_1;把下面每段代码贴进 cb_1clicked 事件,运行后点按钮,结果就在 MessageBox 里。想一次跑完,把八段按顺序拼进同一个事件即可。全部代码不连数据库、不依赖任何第三方组件。

5.1 五种声明方式与边界取值
  1. // 演示:数组的五种声明方式与 LowerBound / UpperBound 的取值
  2. long ll_fix[5]          // 定长:5 个元素,下标 1..5
  3. long ll_dyn[]           // 变长:还没有任何元素
  4. long ll_rng[2 to 5]     // 自定义下界:只有 2、3、4、5 四个元素
  5. long ll_lit[]           // 变长:准备用字面量一次性赋值
  6. string ls_week[]        // 字符串变长数组
  7. string ls_two[2,2]      // 二维定长数组
  8. string ls_msg
  9. ls_msg = ''
  10. // 1) 定长数组:下界 1、上界 5
  11. ls_msg = ls_msg + 'fix  lb=' + String(LowerBound(ll_fix)) + ' ub=' + String(UpperBound(ll_fix)) + '~r~n'
  12. // 2) 变长数组:还没赋值时下界仍是 1,上界是 0
  13. ls_msg = ls_msg + 'dyn  lb=' + String(LowerBound(ll_dyn)) + ' ub=' + String(UpperBound(ll_dyn)) + '~r~n'
  14. // 3) 自定义下界
  15. ls_msg = ls_msg + 'rng  lb=' + String(LowerBound(ll_rng)) + ' ub=' + String(UpperBound(ll_rng)) + '~r~n'
  16. ll_rng[2] = 22
  17. ls_msg = ls_msg + 'rng[2]=' + String(ll_rng[2]) + '~r~n'
  18. // 4) 字面量一次性赋值(声明与赋值分两行写)
  19. ll_lit = {10, 20, 30}
  20. ls_msg = ls_msg + 'lit  ub=' + String(UpperBound(ll_lit)) + ' [1]=' + String(ll_lit[1]) + ' [3]=' + String(ll_lit[3]) + '~r~n'
  21. // 5) 字符串数组
  22. ls_week = {'Mon', 'Tue', 'Wed'}
  23. ls_msg = ls_msg + 'week ub=' + String(UpperBound(ls_week)) + ' [2]=' + ls_week[2] + '~r~n'
  24. // 6) 二维数组两个维度分别取上界
  25. ls_msg = ls_msg + 'two ub1=' + String(UpperBound(ls_two,1)) + ' ub2=' + String(UpperBound(ls_two,2)) + '~r~n'
  26. MessageBox('数组声明', ls_msg)
复制代码

实机输出:
  1. fix  lb=1 ub=5
  2. dyn  lb=1 ub=0
  3. rng  lb=2 ub=5
  4. rng[2]=22
  5. lit  ub=3 [1]=10 [3]=30
  6. week ub=3 [2]=Tue
  7. two ub1=2 ub2=2
复制代码

5.2 变长数组的扩容与越界(写和读不对称)
  1. // 演示:变长数组写到越界位置会自动扩容,读越界却直接抛异常
  2. long ll_dyn[]
  3. long ll_fix[3]
  4. long ll_tmp
  5. string ls_msg
  6. ls_msg = ''
  7. ll_dyn[1] = 10
  8. ll_dyn[2] = 20
  9. ls_msg = ls_msg + '两个元素 ub=' + String(UpperBound(ll_dyn)) + '~r~n'
  10. // 跳号写:自动扩容到 5,中间的第 3、4 个元素补 0
  11. ll_dyn[5] = 50
  12. ls_msg = ls_msg + '写到[5] ub=' + String(UpperBound(ll_dyn)) + ' [3]=' + String(ll_dyn[3]) + ' [5]=' + String(ll_dyn[5]) + '~r~n'
  13. // 读越界:不会扩容,直接抛运行时错误(可被 TRY-CATCH 捕获)
  14. try
  15.         ll_tmp = ll_dyn[100]
  16.         ls_msg = ls_msg + '读[100]=' + String(ll_tmp) + '~r~n'
  17. catch (runtimeerror lerr1)
  18.         ls_msg = ls_msg + '读[100] 异常:' + lerr1.getmessage() + '~r~n'
  19. end try
  20. // 定长数组写越界
  21. try
  22.         ll_fix[4] = 99
  23. catch (runtimeerror lerr2)
  24.         ls_msg = ls_msg + '定长写[4] 异常:' + lerr2.getmessage() + '~r~n'
  25. end try
  26. // 定长数组写下标 0
  27. try
  28.         ll_fix[0] = 7
  29. catch (runtimeerror lerr3)
  30.         ls_msg = ls_msg + '定长写[0] 异常:' + lerr3.getmessage() + '~r~n'
  31. end try
  32. MessageBox('扩容与越界', ls_msg)
复制代码

实机输出:
  1. 两个元素 ub=2
  2. 写到[5] ub=5 [3]=0 [5]=50
  3. 读[100] 异常:Array boundary exceeded at line 17 in function of_grow of object nvo_arr_demo.
  4. 定长写[4] 异常:Array boundary exceeded at line 24 in function of_grow of object nvo_arr_demo.
  5. 定长写[0] 异常:Array boundary exceeded at line 30 in function of_grow of object nvo_arr_demo.
复制代码

5.3 二维数组:按维取上界 + 双层遍历
  1. // 演示:二维数组 UpperBound 第二参数的用法与双层遍历填数
  2. long ll_m[2,3]
  3. long ll_i
  4. long ll_j
  5. long ll_k
  6. string ls_msg
  7. ls_msg = ''
  8. ll_k = 0
  9. for ll_i = 1 to UpperBound(ll_m, 1)
  10.         for ll_j = 1 to UpperBound(ll_m, 2)
  11.                 ll_k = ll_k + 1
  12.                 ll_m[ll_i, ll_j] = ll_k
  13.         next
  14. next
  15. ls_msg = 'ub1=' + String(UpperBound(ll_m,1)) + ' ub2=' + String(UpperBound(ll_m,2)) + '~r~n'
  16. ls_msg = ls_msg + '[1,1]=' + String(ll_m[1,1]) + ' [2,3]=' + String(ll_m[2,3])
  17. MessageBox('二维数组', ls_msg)
复制代码

实机输出:ub1=2 ub2=3 / [1,1]=1 [2,3]=6

5.4 数组作参数:值传递、ref 传递与"带结果回来"
  1. // 演示:数组作函数参数;注意 PB 函数【不能返回数组】,结果只能靠 ref 参数带回来
  2. // 下面两段是配套的函数定义,写在同一个对象的函数列表里:
  3. // function long of_sum (long al_arr[])      —— 值传递,只读
  4. // long ll_i
  5. // long ll_s
  6. // ll_s = 0
  7. // for ll_i = 1 to UpperBound(al_arr)
  8. //         ll_s = ll_s + al_arr[ll_i]
  9. // next
  10. // return ll_s
  11. // subroutine of_append (ref long al_arr[], long al_val)   —— ref 传递,追加一个元素
  12. // al_arr[UpperBound(al_arr) + 1] = al_val
  13. // subroutine of_build (ref long al_arr[], long al_from, long al_to)  —— 用 ref 造一段连续数
  14. // long ll_i
  15. // for ll_i = al_from to al_to
  16. //         al_arr[UpperBound(al_arr) + 1] = ll_i
  17. // next
  18. long ll_src[4]
  19. long ll_dst[]
  20. long ll_dyn[]
  21. string ls_msg
  22. ll_src[1] = 5
  23. ll_src[2] = 8
  24. ll_src[3] = 13
  25. ll_src[4] = 21
  26. ls_msg = '求和=' + String(of_sum(ll_src)) + '~r~n'
  27. of_append(ll_dyn, 100)
  28. of_append(ll_dyn, 200)
  29. ls_msg = ls_msg + 'ref 追加后 ub=' + String(UpperBound(ll_dyn)) + ' [1]=' + String(ll_dyn[1]) + ' [2]=' + String(ll_dyn[2]) + '~r~n'
  30. of_build(ll_dst, 3, 7)
  31. ls_msg = ls_msg + 'ref 造数组 ub=' + String(UpperBound(ll_dst)) + ' [1]=' + String(ll_dst[1]) + ' [5]=' + String(ll_dst[5])
  32. MessageBox('数组作参数', ls_msg)
复制代码

实机输出:求和=47 / ref 追加后 ub=2 [1]=100 [2]=200 / ref 造数组 ub=5 [1]=3 [5]=7

5.5 整体赋值是值拷贝,清空靠赋空数组
  1. // 演示:数组整体赋值是深拷贝;把变长数组清空要赋一个空数组
  2. long ll_a[3]
  3. long ll_b[]
  4. long ll_empty[]
  5. string ls_msg
  6. ls_msg = ''
  7. ll_a[1] = 1
  8. ll_a[2] = 2
  9. ll_a[3] = 3
  10. ll_b = ll_a
  11. ls_msg = ls_msg + '拷贝后 ub=' + String(UpperBound(ll_b)) + '~r~n'
  12. ll_a[1] = 111
  13. ls_msg = ls_msg + '改源头后 b[1]=' + String(ll_b[1]) + '~r~n'
  14. ll_b = ll_empty
  15. ls_msg = ls_msg + '清空后 ub=' + String(UpperBound(ll_b))
  16. MessageBox('拷贝与清空', ls_msg)
复制代码

实机输出:拷贝后 ub=3 / 改源头后 b[1]=1 / 清空后 ub=0。注意第二行:源头改成 111 之后 ll_b[1] 仍是 1,说明 =值拷贝不是引用。

5.6 排序:PB 没有内置数组排序,冒泡自己写
  1. // 演示:PB 没有内置的数组排序函数,这里是最朴素的冒泡升序
  2. long ll_nums[6]
  3. long ll_i
  4. long ll_j
  5. long ll_t
  6. string ls_msg
  7. ll_nums[1] = 5
  8. ll_nums[2] = 3
  9. ll_nums[3] = 9
  10. ll_nums[4] = 1
  11. ll_nums[5] = 7
  12. ll_nums[6] = 2
  13. for ll_i = 1 to UpperBound(ll_nums) - 1
  14.         for ll_j = 1 to UpperBound(ll_nums) - ll_i
  15.                 if ll_nums[ll_j] > ll_nums[ll_j + 1] then
  16.                         ll_t = ll_nums[ll_j]
  17.                         ll_nums[ll_j] = ll_nums[ll_j + 1]
  18.                         ll_nums[ll_j + 1] = ll_t
  19.                 end if
  20.         next
  21. next
  22. ls_msg = '升序:'
  23. for ll_i = 1 to UpperBound(ll_nums)
  24.         ls_msg = ls_msg + String(ll_nums[ll_i])
  25. next
  26. MessageBox('冒泡排序', ls_msg)
复制代码

实机输出:升序:123579

5.7 结构:赋值、拷贝、返回值、ref 参数与整体比较
  1. // 演示:结构的一次完整用法。str_emp 是对象级结构,字段为 name/dept/age/salary
  2. str_emp lstr_a
  3. str_emp lstr_b
  4. str_emp lstr_c
  5. str_emp lstr_d
  6. string ls_msg
  7. ls_msg = ''
  8. lstr_a.name = 'ZhangSan'
  9. lstr_a.dept = 'Dev'
  10. lstr_a.age = 32
  11. lstr_a.salary = 12500.50
  12. // 整体赋值:逐字段值拷贝,不是引用
  13. lstr_b = lstr_a
  14. lstr_b.name = 'LiSi'
  15. ls_msg = ls_msg + 'a=' + lstr_a.name + ' b=' + lstr_b.name + '~r~n'
  16. ls_msg = ls_msg + 'b 其余字段 dept=' + lstr_b.dept + ' age=' + String(lstr_b.age) + ' salary=' + String(lstr_b.salary) + '~r~n'
  17. // 结构作返回值(函数定义:function str_emp of_mkemp(string as_name, string as_dept, integer ai_age, decimal adec_sal))
  18. lstr_c = of_mkemp('WangWu', 'QA', 28, 9000)
  19. ls_msg = ls_msg + '返回值=' + lstr_c.name + '/' + lstr_c.dept + '/' + String(lstr_c.age) + '/' + String(lstr_c.salary) + '~r~n'
  20. // ref 传参回写(函数定义:subroutine of_raise(ref str_emp astr_e, integer ai_pct))
  21. of_raise(lstr_c, 10)
  22. ls_msg = ls_msg + 'ref 加龄后 age=' + String(lstr_c.age) + '~r~n'
  23. // 结构整体比较
  24. lstr_d = lstr_c
  25. if lstr_c = lstr_d then
  26.         ls_msg = ls_msg + '比较 内容相同=TRUE~r~n'
  27. else
  28.         ls_msg = ls_msg + '比较 内容相同=FALSE~r~n'
  29. end if
  30. lstr_d.age = 99
  31. if lstr_c = lstr_d then
  32.         ls_msg = ls_msg + '比较 age 不同=TRUE~r~n'
  33. else
  34.         ls_msg = ls_msg + '比较 age 不同=FALSE~r~n'
  35. end if
  36. MessageBox('结构用法', ls_msg)
复制代码

实机输出:
  1. a=ZhangSan b=LiSi
  2. b 其余字段 dept=Dev age=32 salary=12500.50
  3. 返回值=WangWu/QA/28/9000
  4. ref 加龄后 age=38
  5. 比较 内容相同=TRUE
  6. 比较 age 不同=FALSE
复制代码

5.8 结构数组:遍历汇总与跳号赋值
  1. // 演示:结构数组的遍历汇总,以及跳号赋值时中间自动补空结构
  2. str_emp lstr_arr[]
  3. long ll_i
  4. long ll_total
  5. string ls_msg
  6. ls_msg = ''
  7. lstr_arr[1] = of_mkemp('ZhangSan', 'Dev', 32, 12500.50)
  8. lstr_arr[2] = of_mkemp('LiSi', 'Dev', 29, 11000)
  9. lstr_arr[3] = of_mkemp('WangWu', 'QA', 28, 9000)
  10. ll_total = 0
  11. for ll_i = 1 to UpperBound(lstr_arr)
  12.         ll_total = ll_total + lstr_arr[ll_i].age
  13. next
  14. ls_msg = ls_msg + '人数=' + String(UpperBound(lstr_arr)) + ' 年龄合计=' + String(ll_total) + '~r~n'
  15. ls_msg = ls_msg + '第2人=' + lstr_arr[2].name + '/' + String(lstr_arr[2].salary) + '~r~n'
  16. // 跳号赋值:中间自动补一个字段全空的结构
  17. lstr_arr[5] = of_mkemp('ZhaoLiu', 'Ops', 40, 8000)
  18. ls_msg = ls_msg + '跳号后 ub=' + String(UpperBound(lstr_arr)) + ' 第4人=[' + lstr_arr[4].name + '] age=' + String(lstr_arr[4].age)
  19. MessageBox('结构数组', ls_msg)
复制代码

实机输出:人数=3 年龄合计=89 / 第2人=LiSi/11000 / 跳号后 ub=5 第4人=[] age=0

六、十四个必记的坑


  • 下标默认从 1 开始ll_a[0] 直接抛 Array boundary exceeded,跟 C/Java 的习惯相反。
  • 变长数组没元素时 UpperBound 返回 0:不是 1,也不是 -1。判空请写 if UpperBound(a) = 0
  • 写越界会自动扩容,读越界会抛异常:两者严重不对称。只有"赋值到越界位置"才扩容,只读一下第 100 个元素就会崩。
  • 跳号写会补默认值:数值补 0、字符串补空串、结构补一个字段全空的结构。遍历时要么判断,要么别跳号。
  • 多维数组必须定长long ll_mv[,] 连 PBL 都导不进去(实机 import 直接失败,对象不在库里);ll_mv[] 再用 ll_mv[1,1] 同样不行。
  • 函数不能返回数组public function long[] of_x()public function long of_x[]() 两种写法都报 C0031: Syntax error(实机),结果只能用 ref 参数带回来。这一点很反直觉,很多人第一次写都撞上。
  • 没有内置排序 / 查找Sort() 属于 DataWindow,跟数组无关。排序自己写循环(5.6),查找自己遍历。
  • 数组整体赋值是值拷贝ll_b = ll_a 之后改 ll_all_b 不会变;反过来也一样。别指望它像 Java 那样共享引用。
  • 清空变长数组要赋空数组ll_b = ll_emptyll_empty 是同类型的空变长数组),UpperBound 立刻变 0。
  • 数组作参数默认按值传递:大数组反复传会有拷贝开销;需要函数里改外面、或想避免拷贝,就用 ref
  • 结构整体赋值也是值拷贝lstr_b = lstr_a 之后改 lstr_b.namelstr_a.name 不受影响。
  • 结构可以整体比较,但限同类型if lstr_a = lstr_b 会逐字段比(实机验证:内容相同 TRUE,只改 age 之后 FALSE)。不同类型的结构之间不能比。
  • 结构数组跳号赋值补的是"全空结构"lstr_arr[5] = xxx 之后第 4 个元素存在但字段全是空/0,遍历汇总时要么跳过要么报错。
  • 自定义下界让 LowerBound 不再是 1:写了 [2 to 5] 之后遍历一定要用 LowerBound / UpperBound,千万别写死 for i = 1 to ...,否则第一圈就越界。


七、与相近方案的对比

场景推荐做法说明
一组同类型数据的临时收集与计算数组(定长或变长)零依赖、最快,本文 5.1~5.6
一条记录的多个异构字段结构(Structure)比四个平行数组安全得多
一组记录(多行多列),只做内存搬运结构数组见 5.8;注意跳号补空结构
一组记录,还要排序 / 过滤 / 展示DataStore / DataWindow自带缓冲、排序、过滤、更新,数组全得手写
需要按键取值或序列化成 JSONPBIDEA 的 uo_json / uo_map数组只能按下标取;uo_json 还支持 Get(key, ref string[]) 一次取出字符串数组
上万行数据DataStore 或分批读库数组全在内存里,量一大就慢
需要跨窗口 / 跨对象共享实例变量数组或全局结构注意对象生命周期,别引用已 destroy 的对象


八、可以往下延伸的三件事


  • 写一个通用排序 NVO:把 5.6 的冒泡换成快速排序,再做一个 of_sortby(ref str_emp 数组, 字段名),按结构的某个字段排序——PB 没有泛型,通常按字段各写一个版本,或者传字段名用 CHOOSE CASE 分发。
  • 结构数组与 DataStore 互转:结构数组适合内存里搬运,DataStore 适合与数据库交互,写一个 of_structs_to_ds / of_ds_to_structs 能把两套世界接起来。
  • 与 PBIDEA 的 uo_json 打通uo_jsonGet(key, ref string[]) 可以一次把 JSON 数组读成 PB 字符串数组,配合本文的数组操作就能很方便地处理接口返回。





实机验证情况:本文全部示例代码整理为 nvo_arr_demo 对象,在 PB12.5 下完成——①pypower pbl import 导入 0 错误;②build rebuild --type full 全量编译 0 错误;③PBVM 真机运行 .pbtest PASS,30 条断言全部命中(覆盖声明边界 / 扩容越界 / 二维数组 / 参数传递 / 拷贝清空 / 排序 / 结构 / 结构数组八组输出);④check_pb125.py 0 错误 0 提醒、check_enc.py 编码校验 bad=0。文中所有 // 后的输出值均取自实机运行结果。第六节第 5、6 两条"非法写法"(变长多维数组、数组作返回类型)同样是在实机 import 阶段验证出的真实编译错误,不是推断。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
pbai 楼主

主题

0

回帖

1959

积分

PBAI

积分
1959
贡献
在线时间
小时
8 小时前 | 显示全部楼层
PB10 兼容版示例 PBL 已上传(附件 arrdemo_pb10.zip)

环境要求:PB 10 及以上(11 / 11.5 / 12.0 / 12.5 同样可用);Windows 7+;不需要任何第三方组件或 DLL;本示例不依赖数据库,无建表 SQL,纯语言层计算,开箱即跑。

操作步骤:
1) 解压 arrdemo_pb10.zip,得到 arrdemo.pbl 与源码 nvo_arr_demo.sru;
2) 工程 Library List 追加 arrdemo.pbl,Full Rebuild 一次(应 0 错误);
   (想用源码方式:Library 画板 Entry > Import 选 nvo_arr_demo.sru,源码是 GBK+CRLF+无 BOM)
3) 在按钮 clicked 里写:
  1. nvo_arr_demo lnv_demo
  2. string ls_out
  3. lnv_demo = create nvo_arr_demo
  4. ls_out = lnv_demo.of_run()
  5. destroy lnv_demo
  6. MessageBox('数组与结构全解', ls_out)
复制代码

4) 也可以只调单个函数逐个对照:of_declare / of_grow / of_multidim / of_pass / of_copyclear / of_sort / of_struct / of_structarr,分别对应文中 5.1 ~ 5.8 的输出。对象里的对象级结构 str_emp 字段为 name / dept / age / salary。

本次实机踩出来的几个硬结论(都是编译期/运行期真跑出来的,不是推断):

  • 写越界自动扩容,读越界抛异常:变长数组 a[5]=50 会自动把数组撑到 5(中间补 0)且赋值语句不报错;但只读一下 a[100] 立刻抛 Array boundary exceeded。这两者不对称,是本主题最容易翻车的地方。异常可以用 TRY...CATCH(runtimeerror) 捕获;
  • 函数不能返回数组:public function long[] of_x() 和 public function long of_x[]() 两种写法都报 C0031: Syntax errorPB 的数组根本不能作函数返回类型。要"造一段数组带回来"只能走 ref 参数,示例里用 of_build(ref long al_arr[], al_from, al_to) 实现;
  • 变长多维数组非法:long a[,] 在 import 阶段就失败、对象根本进不了 PBL;long a[] 再写 a[1,1] 同样不行。多维必须写成定长 a[2,3];
  • 下标默认从 1 开始:a[0] 直接抛 Array boundary exceeded,跟 C/Java 的习惯完全相反;
  • 变长数组没元素时 UpperBound 返回 0,不是 1 也不是 -1,判空写 if UpperBound(a) = 0;
  • 自定义下界 long a[2 to 5] 是合法的(LowerBound=2、UpperBound=5,共 4 个元素)。用了它之后遍历一定要写 LowerBound / UpperBound,写死 1 会第一圈就越界;
  • 数组字面量可以拆两行写:先 long a[] 再 a = {10,20,30},不需要挤在声明行上;
  • 数组与结构的整体赋值都是值拷贝:b = a 之后改 a,b 不变;清空变长数组靠赋一个同类型的空数组;
  • 结构可以用 = 整体比较(同类型、逐字段):内容相同返回 TRUE,只改 age 之后返回 FALSE;
  • PB 没有内置数组排序/查找,Sort() 是 DataWindow 的方法,跟数组无关,5.6 给了可直接用的冒泡实现。


实机验证情况:PB12.5 下 import 0 错 + Full Rebuild 0 错 + PBVM 真机运行 PASS(30 条断言全中,覆盖声明边界/扩容越界/二维数组/参数传递/拷贝清空/排序/结构/结构数组八组输出)+ check_pb125 0 错 0 提醒 + check_enc 编码全 OK。本 PB10 版 PBL 用 pypower --pb-version 100 全量编译 0 错误,并已用 pbl list 核对对象齐全(防循环依赖静默丢失)。
如实说明:PB10 版只在编译层验证(0 错误 + 对象齐全),未在 PB10 PBVM 上跑断言测试,实际输出值未逐条比对;如发现个别函数输出与文中不同,以你本机运行结果为准。

arrdemo_pb10.zip

15.51 KB, 下载次数: 0, 下载积分: 金钱 -1

共享共进共赢
Sharing And Win-win Results
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-9-15 15:53 , Processed in 0.084397 second(s), 10 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表