- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
在 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.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 文件将所有内容放在一起。我正在使用 4 个插件:
kotlin-maven-plugin
负责编译 Kotline 文件。配置包括执行kapt处理 AspectJ 注释的插件。jcabi-maven-plugin
执行 AspectJ compiler/weaver将方面编织到二进制类中。maven-jar-plugin
使用引用主类的 list 构建 JAR 文件。maven-shade-plugin
建立一个 fat JAR包括所有库依赖项。这是完整的 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/
是否有任何库或框架旨在促进从另一种成熟的编程语言中构建项目? 在 C++、java 等编程语言中指定逻辑、集合和复杂规则非常容易,但在 Makefile 中完成这些事情似乎是一场艰苦的战斗。我还没有深
我有这段代码可以用 clang 编译得很好(即使使用 -Weverything),但是 gcc 会发出错误。 #include #include #include using namespace
我有以下 block 头文件 BKE_mesh.h: /* Connectivity data */ typedef struct IndexNode { struct IndexNode *
我在我的一个项目中遇到了一个奇怪的问题。我的代码库依赖于一个外部库,其中包含一个名为 Dataset 的类. Dataset类私有(private)继承自 std::vector (其中 Sample
当使用 gcc、g++ 或 make 在终端中编译一个小型 C 或 C++ 项目时,我收到以下错误: /tmp/ccG1caGi.o: In function `main': main.c:(.tex
我正在尝试从 CVS 为 Windows 上的 Emacs 23.1.50 编译 CEDET,但在“第 6 步:打开 EDE...”时出现错误:“defvar:作为变量的符号值是无效的:cedet-m
我正在(重新)学习编程,我从 C 开始。我的 IDE(如果我可以这么说)是 Windows7 上的 cygwin(32 位)和 Visual-Studio 2010。我总是编译我用 gcc (cygw
我喜欢在模板类中使用本地类来执行类似“static if”的构造。但是我遇到了 gcc 4.8 不想编译我的代码的问题。但是 4.7 可以。 这个例子: #include #include #in
我有一个项目,必须仅使用 java 1.4 进行编译。但我计划使用mockito 编写一些单元测试。我想要一种在 pom 中指定的方法,以便 src/main/java 使用 jdk 1.4 编译,但
我想了解 PHP 编译过程是如何工作的。 假设我有一个名为funcs.php 的文件并且这个文件有三个函数,如果我include 或require 它,所有的在文件加载期间编译三个函数?或者源代码会被
编译工具链 我们写程序的时候用的都是集成开发环境 (IDE: Integrated Development Environment),集成开发环境可以极大地方便我们程序员编写程序,但是配置起来
当我编写一些 Scala 代码时,在尝试编译代码时收到一条奇怪的错误消息。我将代码分解为一个更简单的代码(从语义的角度来看这完全没有意义,但仍然显示了错误)。 scala> :paste // Ent
我正在编译一个 SCSS 文件,它似乎删除了我的评论。我可以使用什么命令来保留所有评论? >SASS input.scss output.css 我在 SCSS 中看到两种类型的注释。 // Comm
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
当您编译 grails war 时,我知道 .groovy 代码被编译为字节码类文件,但我不明白容器(例如 tomcat)如何在请求 GSP 时知道如何编译它们。容器了解 GSP 吗?安装在服务器上的
我正在努力将多个文件编译成一个通用程序。我收到一个错误: undefined reference to 'pi' 这是我的代码和 Makefile 的框架。我做错了什么?谢谢! 文件:calcPi.c
我尝试使用 LD_PRELOAD 来 Hook sprintf function ,所以我将打印到缓冲区的结果: #define _GNU_SOURCE #include #include int
我正在寻找最简单的方法来自动将 CoffeeScript 重新编译为 JS。 阅读documentation但仍然很难得到我想要的东西。 我需要它来监视文件夹 src/ 中的任何 *.coffee 文
我想使用定制waveformjs 。我发现this on SO但是,我不知道如何编译/安装波形来开始。我从 GitHub 克隆它并进行了更改,但是我不知道如何将其转换为 .js 文件。 最佳答案 为了
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我是一名优秀的程序员,十分优秀!