|
|
目录
一、zlang简介
二、更新日志
三、技术专栏
3.1. 《zlang不需要getter、setter八股文》
3.2. 《构造和解析二进制数据包》
--------------------------------
zlang是一门完全国产自研的、追求干净观感的、基于对象克隆、支持中文编程的编程语言:
•
完全从底层开始编写,语言引擎(词法 / 语法分析等)、对象库等均未基于 / 采用任何已有语言进行改造、包装或扩展,保证了代码和权利的干净、清晰与自主可控。
•
定位:简洁、高效、易上手、全栈能力,兼顾开发效率与运行性能。
•
设计理念:解决主流语言痛点(如 C 语言字符串处理繁琐、Java 冗余的 Getter/Setter),融合优势并加入创新设计。
•
对标语言:Python。
•
LOGO:中华狸花猫,象征独立、坚韧、不畏挑战。
一、Hello world
- import stdtypes stdio ;
- function int main( array args )
- {
- stdout.Println( "Hello world" );
- return 0;
- }
复制代码 二、核心亮点(5 大特色)
1. 完全从底层自研,自主可控,国产编程语言
•
不基于任何其它语言/框架/引擎的改造或扩展,核心技术100%自研,真正自主可控;
•
产品起源于中国,完全中国制造,填补了国内原创编程语言领域的空白,和世界一起推动编程语言发展;
2. 原生中文编程,降低门槛
•
原生支持中文关键字和标识符,提供对中文编程的良好支持,打破英文编程的传统壁垒,适配国人的文字习惯,降低编程入门门槛,助力编程教育普及,让软件技术更贴合本土场景;
3. 创新语法设计,简洁高效
•
源于C/C++/Java又发展创新:C/Java的语法已经设计的相当完美了,新语言根本没必要完全设计一套新的语法,zlang语法继承自C/C++/Java,能让最广大同学们快速学习掌握;
•
极简哲学,万物皆对象:摒弃class,进化面向对象思想,声明变量即复制对象,简化和统一对象体系;
•
语义直观,减少冗余注解:支持带空格、符号、汉字等的标识符命名;在Web开发中,允许以HTTP 方法与 URL来定义函数名(如 function GET /api/user(){ ... }),无需额外注解,减少命名工作,让代码语义一目了然,大幅降低开发量;
•
以后不用写Getter/Setter繁琐代码了:没必要为了将来1%的扩展性导致99%都遵循繁琐的写法,zlang`提供了属性拦截器解决扩展性问题;
•
对异常处理体系的重新思考和实践;
•
吸取了很多语言的优秀精华:比如atomic、defer等;
4. 完整生态,开箱即用
•
官方标准库内置微整型、短整型、整形、长整型、浮点型、双浮点型、布尔型、字符串型、函数指针型等基础对象;
•
官方标准库内置数组、链表、映射、队列、栈、有序堆、树、缓冲区等数据容器;
•
官方标准库内置大数运算、日期时间、文件、输入输出、随机数、编码、缓存、JSON、XML、MSOffice、线程、日志等对象库;
•
官方标准库内置了加解密对象库,支持常用MD5、SHA1、SHA256、SHA512、DES、3DES、AES、RSA、SM2、SM3、SM4等算法,以及秘钥管理;
•
官方标准库内置了互斥量、读写锁、条件变量、内存屏障等线程同步机制;
•
官方标准库内置数据库对象库支持MySQL、PostgreSQL、Sqlite数据库;
•
官方标准库内置网络对象ip、netaddress、tcp、udp、http、httpclient、httpserver、htmlsection,自带高性能HTTP服务+网页模板引擎套装,支持Web应用开发;
•
官方还提供了跨平台图形界面库开源项目gtk-zlang,支持Windows、Linux桌面应用开发;
5. 高性能 + 跨平台
•
语言内核+对象库用C实现,耗时极低,压测验证性能稳定,静态网页 TPS 达 25000(5 并发),动态网页 RT 5~30ms(单个网页后端含 5 条结果集查询 SQL、23 条单记录查询 SQL、1 条插入 SQL)。
•
支持 Windows、Linux (glibc>=2.17) 跨平台编译与运行。
三、快速开始
1.
源码仓库地址:https://gitee.com/calvinwilliams/zlang (仓库内含整套源代码、测试用例与详细介绍)
2.
环境要求:Windows、Linux (glibc>=2.17)
四、关于作者
zlang由独立开发者calvinwilliams从零研发,历时多年打造。
zlang文档传送门
zlang技术专栏传送门
--------------------------------
0.12.2.0 2026-08-13 calvin
* 调整调试宏架构
* 对象zruntime新增函数PrintObjectBase(object)、PrintObjectFunctions(object)、PrintObjectProperties(object)
* 解决对象内的属性集合实体的循环引用的缺陷
0.12.1.0 2026-08-09 calvin
* 对象poller新增支持定时器
* 修复了原子机制的一个问题
0.12.0.0 2026-08-07 calvin
* 对象eventfd新增函数SetFd、IsValid、GetFd
* 对象thread、queue新增函数BindEventFd(eventfd)、GetFd;多路复用适用对象扩充到线程和消息队列了
* zlang启动参数新增"--child-*-level"
0.11.13.2 2026-08-05 calvin
* 性能优化
0.11.13.1 2026-08-03 calvin
* 内部做了小调整
* 回归测试脚本输出带颜色了
0.11.13.0 2026-07-31 calvin
* 同步了network文档中的返回值和异常说明
* 新增对象eventfd
* 现在子线程返回如果带致命错误会传递给主线程了
0.11.12.0 2026-07-30 calvin
* ip对象新增函数CreateFromDefaultGateway、CreateFromViaConnectingGateway、SetFromDefaultGateway、SetFromViaConnectingGateway
0.11.11.0 2026-07-28 calvin
* netaddress对象新增函数GetIpInteger、Create(uint,ushort)、Set(uint,ushort)
* 对象-缓冲区转换函数支持跟踪当前偏移量了
* 修复了启动线程时未把当前对象和函数传入环境上下文的问题
* 调整了一批全局API名字
* 根对象新增函数GetDirectPropertySize、GetPropertiesDirectPropertySize
0.11.10.0 2026-07-27 calvin
* 所有数值类对象都增加ToTiny~ToULong~ToDouble系列函数
* 各网络对象明确了超时类型、端口类型、数据长度类型,以及更新相关函数原型
* buffer对象新增函数ResizeElementCount、GetSize
0.11.9.1 2026-07-25 calvin
* 重构了zexception对象,一劳永逸的解决了zexception和string加载优先级悖论
* 补充thread对象,如果是非守护线程,子线程结束后会把致命错误和异常传回主线程
0.11.9.0 2026-07-24 calvin
* 新增pipe对象
* 对象poller支持pipe对象
0.11.8.0 2026-07-23 calvin
* TEST_RUNTIME_LEVEL对内性能优化
* string对象增加内置小缓存区以减少内存块分配次数,整个string对象代码做了调整
* ZlangRuntime一些成员移到ZlangGlobalEnvironment,真正把ZlangGlobalEnvironment用起来
0.11.7.0 2026-07-22 calvin
* 新增zlang命令行参数--builtin-parameters或-B用于显示所有内部缺省参数
* 修正了基础类型升级的问题
0.11.6.0 2026-07-21 calvin
* 解开了一些类型检查硬性约束,更有适配性和灵活度
* 输出格式化增加内嵌非基础变量自动调用ToString
* 重整C开发zlang对象库模板zlang_c_object而调整一些地方,完善文档
--------------------------------
《zlang不需要getter、setter八股文》
getter、setter八股文
目前很多编程语言都有getter、setter八股文,本人很是反感,这也是创造zlang的主要原因之一。
getter、setter的作用是解耦 调用者代码 和 被调对象字段代码,其实现在IDE已经很智能了,换名字就是一键的事情。
Java
- class MyClass
- {
- private int age ;
- public MyClass() {
- }
- public int getAge()
- {
- return age;
- }
- public void setAge( int age )
- {
- this.age = age ;
- }
- }
- public class Main {
- public static void main(String[] args) {
- MyClass o = new MyClass();
- o.setAge(25);
- System.out.println(o.getAge());
- }
- }
复制代码 zlang不需要getter、setter八股文
zlang设计成不需要getter、setter八股文,代码理解直观,代码量大幅减少,产出提效。
zlang
- object MyObject
- {
- int age ;
- }
- function int main( array args )
- {
- MyObject o ;
- o.age = 25 ;
- stdout.FormatPrintln( o.age );
- }
复制代码 getter、setter允许“存取字段值时可以做一些转换”
还有人解释getter、setter允许“存取字段值时可以做一些转换”,你评估一下真实项目中有多少需要转换的需求,为了所谓的将来莫须有的扩展性,造成所有代码中都无谓充斥着大量getter、setter是一种愚蠢和低效。
Java
- class MyClass
- {
- private int age ;
- public MyClass() {
- }
- public int getAge()
- {
- return age;
- }
- public void setAge( int age )
- {
- if (age < 0 || age > 300) {
- throw new IllegalArgumentException( "age invalid" );
- this.age = age ;
- }
- }
- public class Main {
- public static void main(String[] args) {
- try {
- MyClass o = new MyClass();
- o.setAge(25);
- System.out.println(o.getAge());
- } catch (IllegalArgumentException e) {
- System.out.println("EXCEPTION:" + e.getMessage());
- }
- }
- }
复制代码 `zlang有属性拦截器
你会问,那么将来有字段存取过程需要转换怎么办?zlang的回答是:用属性拦截器。1%的字段需要转换,就写1%的字段属性拦截器,而不是写100%的getter、setter,不多写一个字符,干净利落。
zlang
- import stdtypes stdio ;
- object MyObject
- {
- int age ;
- intercept set age( object age )
- {
- if( age < 0 || age > 300 )
- {
- zexception.SetException(-1,"age invalid");
- return;
- }
- this.age = age ;
- return;
- }
- }
- function int main( array args )
- {
- try
- {
- MyObject o ;
- o.age = -1 ;
- stdout.FormatPrintln( o.age );
- catch
- {
- stdout.Println( zexception.GetExceptionDesc() );
- }
- }
- }
复制代码 执行效果
- $ zlang zlang_dont_need_getter_setter.z
- age invalid
复制代码
--------------------------------
《构造和解析二进制数据包》
zlang的缓冲区对象buffer特别适合构造和解析二进制数据包,下面以IP数据包为例,介绍zlang如何编写代码来构造和解析二进制数据包。
之所以选择IP数据包并不是鼓励用zlang处理网络协议栈,而是觉得IP数据包是典型的二进制数据包的研究案例。
构造总体思路
•
定义一个数据包对象,按顺序定义各字段(注意字段的字长;如果只取字段的几个比特,在字段名后面加上位域:(bit_fields);如果多个字段的位段映射到目标缓冲区中的一个字节,写对位域即可);
•
用缓冲区对象函数ResizeElementCount调整好缓冲区对象内部缓冲区大小;
•
为不影响父级对象,克隆子对象;填充子对象各字段的值;子对象缺省继承根对象zobject,调用根对象函数DumpBuffer倾倒到缓冲区对象缓冲区中;
•
IP数据包头还有附带区域,可以在倾倒缓冲区后附加倾倒一个字符串;
•
倾倒后调用标准输出对象函数HexPrintln按十六进制打印输出缓冲区;(可选)
编写构造具体代码段
定义IP数据包对象:
- object ip_package
- {
- utiny version:4 ;
- utiny ihl:4 ;
- utiny tos ;
- ushort total_length ;
- ushort identification ;
- utiny flags:3 ;
- ushort fragment_offset:13 ;
- utiny ttl ;
- utiny protocol ;
- ushort header_checksum ;
- uint source_ip ;
- uint dest_ip ;
- }
复制代码
调整好缓冲区对象内部缓冲区大小:
- ip_packet_head_size = ip_package.GetPropertiesDirectPropertySize() ;
- ip_packet_payload_size = (payload.Length()+4)/5*5 ;
- ip_packet_size = ip_packet_head_size + ip_packet_payload_size ;
- stdout.FormatPrintln( "ip_packet_head_size[%d]B + ip_packet_payload_size[%d]B = ip_packet_size[%d]B" , ip_packet_head_size , ip_packet_payload_size , ip_packet_size );
- buf.ResizeElementCount( ip_packet_size );
复制代码
填充子对象各字段的值:
- ipp1..;
- ..version = 4b0100UT ;
- ..ihl = 5UT ;
- ..tos = 8b00000000UT ;
- ..total_length = ip_packet_size.ToUShort() ;
- ..identification = 0x1234US ;
- ..flags = 3b010UT ;
- ..fragment_offset = 4098US ;
- ..ttl = 64UT ;
- ..protocol = 6UT ;
- ..header_checksum = 0US ;
- ..source_ip = ip.CreateFromString("192.168.0.1").ToIntegerInHostOrder();
- ..dest_ip = ip.CreateFromString("192.168.0.2").ToIntegerInHostOrder();
复制代码
倾倒各字段以及附带区域到缓冲区:
- offset = 0 ;
- ipp1.DumpBuffer( buf , offset );
- buf.CopyIntoAsVString( offset , payload );
复制代码
按十六进制打印输出缓冲区:
- stdout.HexPrintln( buf );
复制代码 解析总体思路
•
已经定义好了数据包对象;拿到构造好的缓冲区对象;
•
设置解析偏移量为0,调用缓冲区对象函数ToEntityObject解析到数据包对象中各字段;偏移量自动前进;
•
IP数据包头还有附带区域,计算出附带区域大小,调用缓冲区对象函数CopyOutAsVString解析到字符串中;
编写解析具体代码段
解析缓冲区对象到数据包对象中各字段:
- offset = 0 ;
- buf.ToEntityObject( <object>ipp2 , offset );
复制代码
解析附带区域:
- buf.CopyOutAsVString( offset , payload2 , buf.GetSize()-ip_package.GetPropertiesDirectPropertySize() );
复制代码 构造和解析的完整源代码
源文件名:tech-notes/binary-packet.z
- import stdtypes stdio network ;
- object ip_package
- {
- utiny version:4 ;
- utiny ihl:4 ;
- utiny tos ;
- ushort total_length ;
- ushort identification ;
- utiny flags:3 ;
- ushort fragment_offset:13 ;
- utiny ttl ;
- utiny protocol ;
- ushort header_checksum ;
- uint source_ip ;
- uint dest_ip ;
- }
- function void PrintlnIpPackage( ip_package ipp , string payload )
- {
- stdout.FormatPrintln( "ipp.version[%{ipp.version}]" );
- stdout.FormatPrintln( "ipp.ihl[%{ipp.ihl}]" );
- stdout.FormatPrintln( "ipp.tos[%{ipp.tos}]" );
- stdout.FormatPrintln( "ipp.total_length[%{ipp.total_length}]" );
- stdout.FormatPrintln( "ipp.identification[0x%04x]" , ipp.identification );
- stdout.FormatPrintln( "ipp.flags[%{ipp.flags}]" );
- stdout.FormatPrintln( "ipp.fragment_offset[%{ipp.fragment_offset}]" );
- stdout.FormatPrintln( "ipp.ttl[%{ipp.ttl}]" );
- stdout.FormatPrintln( "ipp.protocol[%{ipp.protocol}]" );
- stdout.FormatPrintln( "ipp.header_checksum[%{ipp.header_checksum}]" );
- stdout.FormatPrintln( "ipp.source_ip[%s]" , ip.CreateFromIntegerInHostOrder(ipp.source_ip).ToString() );
- stdout.FormatPrintln( "ipp.dest_ip[%s]" , ip.CreateFromIntegerInHostOrder(ipp.dest_ip).ToString() );
- stdout.FormatPrintln( "ipp.payload[%s]" , payload );
-
- return;
- }
- function int main( array args )
- {
- try
- {
- ip_package ipp1 , ipp2 ;
- string payload = "helo" ;
- string payload2 ;
- int ip_packet_head_size ;
- int ip_packet_payload_size ;
- int ip_packet_size ;
- buffer<char> buf ;
- int offset ;
-
- ip_packet_head_size = ip_package.GetPropertiesDirectPropertySize() ;
- ip_packet_payload_size = (payload.Length()+4)/5*5 ;
- ip_packet_size = ip_packet_head_size + ip_packet_payload_size ;
- stdout.FormatPrintln( "ip_packet_head_size[%d]B + ip_packet_payload_size[%d]B = ip_packet_size[%d]B" , ip_packet_head_size , ip_packet_payload_size , ip_packet_size );
- buf.ResizeElementCount( ip_packet_size );
-
- ipp1..;
- ..version = 4b0100UT ;
- ..ihl = 5UT ;
- ..tos = 8b00000000UT ;
- ..total_length = ip_packet_size.ToUShort() ;
- ..identification = 0x1234US ;
- ..flags = 3b010UT ;
- ..fragment_offset = 4098US ;
- ..ttl = 64UT ;
- ..protocol = 6UT ;
- ..header_checksum = 0US ;
- ..source_ip = ip.CreateFromString("192.168.0.1").ToIntegerInHostOrder();
- ..dest_ip = ip.CreateFromString("192.168.0.2").ToIntegerInHostOrder();
- stdout.Println( "--- ipp1 ---");
- PrintlnIpPackage( ipp1 , payload );
-
- offset = 0 ;
- ipp1.DumpBuffer( buf , offset );
- buf.CopyIntoAsVString( offset , payload );
- stdout.HexPrintln( buf );
-
- offset = 0 ;
- buf.ToEntityObject( <object>ipp2 , offset );
- buf.CopyOutAsVString( offset , payload2 , buf.GetSize()-ip_package.GetPropertiesDirectPropertySize() );
- stdout.FormatPrintln( "offset[%d]B" , offset );
- stdout.Println( "--- ipp2 ---");
- PrintlnIpPackage( ipp2 , payload2 );
-
- catch
- {
- stdout.Println( zexception.GetExceptionDesc() );
- }
- }
-
- return 0;
- }
复制代码 执行效果
- $ zlang binary-packet.z
- ip_packet_head_size[20]B + ip_packet_payload_size[5]B = ip_packet_size[25]B
- --- ipp1 ---
- ipp.version[4]
- ipp.ihl[5]
- ipp.tos[0]
- ipp.total_length[25]
- ipp.identification[0x1234]
- ipp.flags[2]
- ipp.fragment_offset[4098]
- ipp.ttl[64]
- ipp.protocol[6]
- ipp.header_checksum[0]
- ipp.source_ip[192.168.0.1]
- ipp.dest_ip[192.168.0.2]
- ipp.payload[helo]
- | 0 1 2 3 4 5 6 7 8 9 A B C D E F | 0123456789ABCDEF
- -----------+-------------------------------------------------+-----------------
- 0x00000000 | 45 00 00 19 12 34 50 02 40 06 00 00 C0 A8 00 01 | E....4P.@.......
- 0x00000010 | C0 A8 00 02 68 65 6C 6F 00 | ....helo.
- offset[25]B
- --- ipp2 ---
- ipp.version[4]
- ipp.ihl[5]
- ipp.tos[0]
- ipp.total_length[25]
- ipp.identification[0x1234]
- ipp.flags[2]
- ipp.fragment_offset[4098]
- ipp.ttl[64]
- ipp.protocol[6]
- ipp.header_checksum[0]
- ipp.source_ip[192.168.0.1]
- ipp.dest_ip[192.168.0.2]
- ipp.payload[helo]
复制代码
原文链接 |
|