对标java注解,仓颉语言宏功能简介

举报
长弓三石 发表于 2024/07/09 07:40:16 2024/07/09
【摘要】 仓颉语言作为一种面向应用层的通用开发语言,和java的开发范围高度重合,在对标java注解这一方向上,仓颉的宏在性能上有一定的优势,因为仓颉的宏是编译期展开的,不需要运行时处理,这样,性能会更高一点。不过,java注解和仓颉的宏并不完全一致,各有各的特点,使用得当的话都可以简化开发工作。

1.什么是仓颉宏

在企业级的软件开发市场,java语言长期处于绝对领先的位置,其中的原因比较多,比如开放性、生态等等,除此之外,java语言在开发过程中的易用性,也为此做出了贡献,比如java中的注解,通过简单的一个标记,就能完成复杂的功能,而spring等第三方框架的出现,更是让注解如虎添翼,大大简化了java程序的开发工作,初学者经过一段时间的培训,就可以使用基于注解的spring进行企业级开发。

仓颉语言作为一种面向应用层的通用开发语言,和java的开发范围高度重合,在对标java注解这一方向上,仓颉的宏在性能上有一定的优势,因为仓颉的宏是编译期展开的,不需要运行时处理,这样,性能会更高一点。不过,java注解和仓颉的宏并不完全一致,各有各的特点,使用得当的话都可以简化开发工作。

2.仓颉宏的定义

仓颉中宏的功能类似于函数,用来对输入的代码序列进行处理,输出处理后的代码序列,这个从输入代码映射到输出代码的过程称为宏展开。

和函数相比,宏定义具有如下特点:

宏定义所在的 package 需使用 macro package 来声明。
宏定义需要使用关键字 macro。
宏定义的输入和输出类型必须是 Tokens。
宏调用需要使用 @。

3.仓颉宏的使用示例

以下的示例代码模拟了登录以及入库、出库、查看库存等动作,包括多个类和顶层函数,假如需要把所有的函数调用都记录日志,也就是记录调用开始和结束的时间,以及传入的参数和返回的值,并且支持日志写入到控制台或者日志文件。

main(): Unit {
    //模拟登录
    if (!login("admin", "qD@0532")) {
        println("用户名或者密码错误!")
        return
    }

    //添加图书
    let book = Book("仓颉语言元编程")

    //模拟入库
    book.input(88)

    //模拟出库
    book.output(66)

    //查看库存
    println(book.stock)
}

//登录
func login(userName: String, password: String): Bool {
    let user = User.getUserByUserName(userName)
    return user.passwd == password
}

//用户
public class User {
    public User(var userId: Int64, var userName: String, var passwd: String) {}

    //根据用户名称查找用户信息
    public static func getUserByUserName(userName: String) {
        return User(1, userName, "qD@0532")
    }
}

public class Book {
    public Book(var bookName: String, var stock: Int64) {}

    public init(bookName: String) {
        this.bookName = bookName
        this.stock = 0
    }

    //入库
    public func input(count: Int64) {
        this.stock += count
        return stock
    }

    //出库
    public func output(count: Int64) {
        this.stock -= count
        return stock
    }
}

要完成这样的功能,常规写法可能需要几百行代码才能实现,而且代码会嵌入到现有的函数中,带来一定的调试困难。但是,如果有了元编程的支持,通过宏定义一切就可以迎刃而解了。

假如已经自定义了一个名称为Cradle的宏,它可以通过切面织入的方式,自动拦截函数的调用,并且按照属性宏的入参来执行向控制台或者日志文件写入日志,那么,针对上面的要求,通过在函数和类的定义位置添加上Cradle宏调用即可,修改后的代码如下:

import cradle.*
from std import time.*
from std import collection.*
from std import fs.*
from std import io.*
from std import os.posix.*

@Cradle
main(): Unit {
    //模拟登录
    if (!login("admin", "qD@0532")) {
        println("用户名或者密码错误!")
        return
    }

    //添加图书
    let book = Book("仓颉语言元编程")

    //模拟入库
    book.input(88)

    //模拟出库
    book.output(66)

    //查看库存
    println(book.stock)
}

//登录
@Cradle[console|logfile]
func login(userName: String, password: String): Bool {
    let user = User.getUserByUserName(userName)
    return user.passwd == password
}

//用户
@Cradle[console|logfile]
public class User {
    public User(var userId: Int64, var userName: String, var passwd: String) {}

    //根据用户名称查找用户信息
    public static func getUserByUserName(userName: String) {
        return User(1, userName, "qD@0532")
    }
}

@Cradle[console|logfile]
public class Book {
    public Book(var bookName: String, var stock: Int64) {}

    public init(bookName: String) {
        this.bookName = bookName
        this.stock = 0
    }

    //入库
    public func input(count: Int64) {
        this.stock += count
        return stock
    }

    //出库
    public func output(count: Int64) {
        this.stock -= count
        return stock
    }
}

可以看到,一共只加了四个注解,没有破坏原来函数的结构,既简单明了,又做到了逻辑分离。

下面是运行后的效果,包括输出到控制台的日志和写入到日志文件的日志:

console.png

logfile.png

通过上述示例,可以看到,基于仓颉元编程的仓颉宏功能还是很强大的,通过自定义宏可以帮助开发者实现天马行空的想法,在注重性能和效率的企业级开发上更是大有可为。

4.仓颉元编程示例获取

《仓颉语言元编程》是由张磊编写,清华大学出版社出版的一本仓颉元编程学习的入门书籍,该书从元编程的概念开始,逐步讲解仓颉元编程的基础知识、抽象语法树的常用用法,以及如何定义和使用仓颉宏。

该书包括将近60个完整的元编程示例,最新示例代码已全面适配仓颉最新的版本0.51.4,并上传到码云,全部可以免费下载:

https://gitee.com/zl3624/cangjie_meta_programming

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。