gpt4 book ai didi

Kotlin:可以在编译期间通过元编程修改函数吗?

转载 作者:IT老高 更新时间:2023-10-28 13:47:25 25 4
gpt4 key购买 nike

在 JavaScript/Python 等动态语言中,可以在运行时覆盖或“修改”函数。例如,为了修改 JS 中的 alert 函数,可以这样做:

const _prev_alert = window.alert;
window.alert = function() {
_prev_alert.apply(this, arguments);
console.log("Alert function was called!");
}

这将输出“Alert function was called!”每次调用 alert 函数时发送到控制台。

现在,由于 Kotlin-JVM 或 Kotlin-Native 的静态特性,显然这样的事情在运行时是不可能的。但是,对于那些相同的语言,是否有可能在编译期间修改非编译函数?我不是指来自库的预编译函数,而是我在我正在开发的同一个项目中编写的函数。

例如,假设我编写了一个名为 get_number 的函数。我可以修改 get_number 以返回不同的数字而不改变它在 main 中的调用方式并且不直接修改它的代码吗? (或者有没有办法我可以编写原始 get_number 以便以后可以进行修改?)

fun main(args: Array<String>) {
println(get_number())
}

fun get_number(): Int {
return 3
}

// Without modifying the code above, can I get main to print something besides 3?

我一直在阅读 Kotlin 的带有注释和反射的元编程,所以也许这些可以控制编译器的行为并覆盖 get_number 的代码?或者这是完全的疯狂,并且这种性质的事情唯一可能的方法是通过在 Kotlin 上开发我自己的、独立的元编程包装器?

另外,再次澄清一下,这个问题与 Kotlin-JS 无关,答案(如果存在)应该适用于 Kotlin-JVM 或 Native。

最佳答案

正如我在评论中所说:在几乎所有情况下,使用适当的设计模式比开始依赖像 dynamic proxies 这样的东西更可取。 , reflection , 或 AOP解决这类问题。

话虽如此,问题是在编译时通过元编程修改 Kotlin 函数是否可能,答案是"is"。为了演示,下面是一个使用 AspectJ 的完整示例。 .


项目结构

我设置了一个小Maven具有以下结构的基于项目:

.
├── pom.xml
└── src
└── main
└── kotlin
├── Aop.kt
└── Main.kt

我将重现以下部分中所有文件的内容。


应用代码

实际的应用程序代码在名为 Main.kt 的文件中,并且——除了我将您的函数重命名为符合 Kotlin naming rules 的事实之外。 -它与您问题中提供的代码相同。 getNumber() 方法旨在返回 3

fun main(args: Array<String>) {
println(getNumber())
}

fun getNumber(): Int {
return 3
}

AOP 代码

AOP相关的代码在Aop.kt中,非常简单。它有一个 @Around 通知,其切入点与 getNumber() 函数的执行相匹配。该通知将拦截对 getNumber() 方法的调用并返回 42(而不是 3)。

import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect

@Aspect
class Aop {
@Around("execution(* MainKt.getNumber(..))")
fun getRealNumber(joinPoint: ProceedingJoinPoint): Any {
return 42
}
}

(注意 Main.kt 文件生成的类的名称如何是 MainKt。)


POM 文件

POM 文件将所有内容放在一起。我正在使用 4 个插件:

这是完整的 POM 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>x.y.z</groupId>
<artifactId>kotlin-aop</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.61</kotlin.version>
<aspectj.version>1.9.1</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.14.1</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>MainKt</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

构建和执行

要构建,与任何 Maven 项目一样,您只需运行:

mvn clean package

这将在 target/kotlin-aop-1.0-SNAPSHOT.jar 位置构建一个胖 JAR。然后可以使用 java 命令执行此 JAR:

java -jar target/kotlin-aop-1.0-SNAPSHOT.jar

执行然后给我们以下结果,证明一切都按预期工作:

42

(应用程序是在撰写本文时使用最新的 Oracle Java 8 JDK — 1.8.0_181 构建和执行的)


结论

如上例所示,重新定义 Kotlin 函数当然是可能的,但是——重申我的原点——在几乎所有情况下,都有更优雅的解决方案可以满足您的需求。

关于Kotlin:可以在编译期间通过元编程修改函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52087239/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com