在Clojure中,我正在使用gen-class
和Java库。程序员通常提供两个实现接口和扩展类的类。这两个类应该互相引用,并且考虑到库的设计方式,很难避免这种循环依赖。
循环不会成为问题 - 编译器不必了解它们 - 除了我试图通过明智地添加类型提示(具有巨大的加速)来优化代码。通过重新组织代码,我已经能够避免编译器关于循环依赖的抱怨,并且我已经将问题简化为单一类型提示:
在一个源文件Foo.clj中,我有这个函数/方法,这是类实现的接口所需要的:
(defn -step
[^Foo this ^Bar bar]
...)
另一个源文件Bar.clj创建了一个Foo实例的集合,所以我必须在那里引用Foo类。在我的Leiningen project.clj中,我有这样的一行:
:aot [Foo Bar]
我没有得到循环依赖性错误。相反,我得到ClassNotFoundException
:如果我在Foo
后首先放置:aot
,编译器会在编译Bar
时抱怨它不知道Foo
,因为^Bar
中的-step
类型提示。如果我在Bar
之后放置:aot
,编译器在编译Foo
时找不到Bar
,因为在Bar.clj中调用了(Foo.)
我目前的解决方案是:
^Bar
定义中的-step
类型提示。-step
中添加类型提示。Foo
(即再次运行'lein compile`)。这是有效的,因为第二次编译Foo
时,Bar
存在,所以编译器不会抱怨。
有没有办法编译这两个类而不删除并添加类型提示? (或者我应该考虑这种情况的另一种方式?)
答案 0 :(得分:1)
我倾向于在foo名称空间中为Foo添加一个工厂函数。
(defn new-foo [] (Foo.)) ; parameterize to your satisfaction
然后您可以在以下答案中使用前向声明技术来访问Bar中的new-foo - Forward-declaring a var from another namespace in Clojure?
这当然仍然很糟糕 - 如果有任何其他方法来打破依赖周期,你可能会采取它。如果有意义的话,如何在同一名称空间中定义Foo和Bar?它们看起来非常紧密耦合,尽管有一个抽象的问题描述很难说。