目录
一、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. 完全从底层自研,自主可控,国产编程语言
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. 高性能 + 跨平台
三、快速开始
-
源码仓库地址:https://gitee.com/calvinwilliams/zlang (仓库内含整套源代码、测试用例与详细介绍)
-
环境要求:Windows、Linux (glibc>=2.17)
四、关于作者
zlang由独立开发者calvinwilliams从零研发,历时多年打造。
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 );
解析总体思路
编写解析具体代码段
解析缓冲区对象到数据包对象中各字段:
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]