目录
一、面向切面
面向切面编程(AOP)是一种编程范式,它是为了解决软件开发横切点的问题。
横切点:整个项目中,多处出现的与核心业务无关却必不可少的功能点,比如:日志记录、性能统计等。
切面:一个切面代表一个模块化的横切关注点,实现了某个关注点的功能。
切入点:切入切面的点。
通知:切面的具体实现,描述了在切面的哪个位置以及如何执行编程逻辑。
// 宏包
macro package Study.define
// 导包
import std.ast.*
import std.collection.*
import std.unicode.*
/*
* 计算函数执行时间
* 非递归函数
*/
public macro MeasureTime(input: Tokens) {
let funcDecl = FuncDecl(input)
// 获取修饰符
let funcModifiers = funcDecl.modifiers
// 获取函数名
let funcName = funcDecl.identifier
// 获取参数列表
let params = funcDecl.funcParams
var returnType = Tokens()
// 获取返回值类型
if (funcDecl.colon.value == ":") {
returnType = quote(: $(funcDecl.declType))
}
// 处理调用函数的实参列表
var funcArgs = ArrayList<Token>()
for (param in params) {
funcArgs.append(param.identifier)
}
var args = Tokens()
if (funcArgs.size == 0) {
args = quote(())
} else if (funcArgs.size == 1) {
args = quote(($(funcArgs[0])))
} else {
args += Token(TokenKind.LPAREN)
for (i in 0..(funcArgs.size - 1)) {
args += funcArgs[i] + Token(TokenKind.COMMA)
}
args += funcArgs[funcArgs.size - 1] + Token(TokenKind.RPAREN)
}
quote(
$funcModifiers func $funcName($params) $returnType {
func inner($params) $returnType $(funcDecl.block)
let startTime = DateTime.now()
let returnValue = inner $args
let endTime = DateTime.now()
println("运行时间:${(endTime - startTime).toMicroseconds()}")
returnValue
}
)
}
package Study
// 导包
import Study.define.*
import std.ast.*
import std.time.*
@MeasureTime
func jieCheng(num: Int64) {
var result = 1
for (i in 1..=num) {
result *= i
}
result
}
main () {
println(jieCheng(20))
}
二、代码生成
在创建类的时候,要为每一个成员变量实现getter和setter函数,如果一个类中的成员变量非常多的话,就会十分麻烦,不易维护,而且代码也会变得十分臃肿,为了解决这个问题,我们可以使用宏,为我们自动生成getter和setter函数。
// 宏包
macro package Study.define
// 导包
import std.ast.*
import std.collection.*
import std.unicode.*
/*
* 自动生成Getter和Setter
*/
public macro GenerateCode(input: Tokens): Tokens{
let classDecl = ClassDecl(input)
let decls = classDecl.body.decls
let propList = ArrayList<Decl>()
for (decl in decls) {
// 只处理变量声明
if (!(decl is VarDecl)) {
continue
}
let varDecl = (decl as VarDecl).getOrThrow()
// 只处理显示声明了类型的变量
if (varDecl.colon.value == ":") {
if (varDecl.keyword.value == "let") {
let propDecl = generateCodeProp(varDecl)
propList.append(propDecl)
} else {
let propDecl = generateCodeMutProp(varDecl)
propList.append(propDecl)
}
}
}
decls.appendAll(propList)
classDecl.toTokens()
}
/*
* 生成属性名
*/
private func generateCodePropName(varDecl: VarDecl): Token {
let varName = varDecl.identifier.value
let arr = varName.toRuneArray()
let propName = "prop${arr[0].toUpperCase()}${arr[1.. arr.size]}"
return Token(TokenKind.IDENTIFIER, propName)
}
/*
* 生成mutprop
*/
private func generateCodeMutProp(varDecl: VarDecl): Decl {
let propName = generateCodePropName(varDecl)
return PropDecl(quote(
mut prop $propName: $(varDecl.declType) {
get() {
$(varDecl.identifier)
}
set(value) {
$(varDecl.identifier) = value
}
}
))
}
/*
* 生成prop
*/
private func generateCodeProp(varDecl: VarDecl): Decl {
let propName = generateCodePropName(varDecl)
return PropDecl(quote(
prop $propName: $(varDecl.declType) {
get() {
$(varDecl.identifier)
}
}
))
}
package Study
// 导包
import Study.define.*
import std.ast.*
@GenerateCode
class Account {
private let id: String
private var name: String
private var age: Int64
private let sex: String
private var money: Float64
init(id: String, name: String, age: Int64, sex: String, money: Float64) {
this.id = id
this.name = name
this.age = age
this.sex = sex
this.money = money
}
}
main () {
let account = Account("1001", "钝子生", 23, "男", 6000.0)
println("id: ${account.propId}")
println("姓名: ${account.propName}")
println("年龄: ${account.propAge}")
println("性别: ${account.propSex}")
println("余额: ${account.propMoney}")
}
三、小结
本章为大家详细的介绍了仓颉编程语言中面向切面和代码生成的内容,下一章,为大家带来宏练习题的内容。最后,创作不易,如果大家觉得我的文章对学习仓颉服务端开发有帮助的话,就动动小手,点个免费的赞吧!收到的赞越多,我的创作动力也会越大哦,谢谢大家🌹🌹🌹!!!