请在2024 Clojure状态调查中分享您的想法!

欢迎!请参阅关于页面以了解更多关于如何使用此功能的信息。

+18
Java互操作

问题

Clojure对Java可变参数方法的调用需要为最后一个参数创建一个对象数组。这是进行互操作时常见混淆的来源。

例如,尝试调用java.util.Collections.addAll(Collection c, T... elements)

user=> (Collections/addAll [] (object-array 0))

Method类提供了一个{{isVarArg()}}方法,可以用于告知编译器不同地处理事情。

http://groups.google.com/group/clojure/browse_thread/thread/7d0d6cb32656a621

最新补丁删除,因为不完整且目标不明确

Java中的可变参数

如目前所述,本工单的范围仅限于省略可变参数,但这只是Clojure处理可变参数与Java不同的情况之一。为了完整性,以下是关于Java如何处理可变参数方法的简要概述,这可能有助于讨论Clojure如何不同地做事情,本工单的目标应该是什么。

假设以下设置

`
public class VarArgs {

public static class SingleVarargMethod {
    public static void m(String arg1, String... args) {}
}

public static class MultipleVarargMethods {
    public static void m(String... args) {}
    public static void m(String arg1) {}
    public static void m(String arg1, String... args) {}
}

}
`

|Java|可能对应的Clojure? |注释|
| :-- | :-- | :-- | :-- |
|{{VarArgs.SingleVarargMethod.m("a");}} | {{(SingleVarargMethod/m "a")}} | |
|{{VarArgs.SingleVarargMethod.m("a", "b");}} | {{(SingleVarargMethod/m "a" "b")}} | |
|{{VarArgs.SingleVarargMethod.m("a", "b", "c");}} | {{(SingleVarargMethod/m "a" "b" "c")}} | |
|{{VarArgs.SingleVarargMethod.m("a", new String[]{"b", "c"});}} | {{(SingleVarargMethod/m "a" (object-array ["b" "c"]))}} | |
|{{VarArgs.MultipleVarargMethods.m();}} | {{(MultipleVarargMethods/m)}} | |
|{{VarArgs.MultipleVarargMethods.m((String) null);}} | {{(MultipleVarargMethods/m nil)}} |使用类型提示来消除歧义?|
|{{VarArgs.MultipleVarargMethods.m((String[]) null);}} | {{(MultipleVarargMethods/m nil)}} |使用类型提示来消除歧义? |
|{{VarArgs.MultipleVarargMethods.m("a", null);}} | {{(MultipleVarargMethods/m "a" nil)}} | |
|{{VarArgs.MultipleVarargMethods.m("a", new String[]{});}} | {{(MultipleVarargMethods/m "a" (object-array 0))}} | |
|{{VarArgs.MultipleVarargMethods.m(new String[]{"a"});}} | {{(MultipleVarargMethods/m (object-array ["a"]))}} | |
|{{VarArgs.MultipleVarargMethods.m("a", new String[]{"b", "c"});}} | {{(MultipleVarargMethods/m "a" (object-array ["b" "c"]))}} | |

13 个回答

0

评论由:importer 发布

http://www.assembla.com/spaces/clojure/tickets/440 转换而来

0

评论由:ataggart 发布

补丁增加了对varargs的支持。基于CLJ-445补丁进行扩展。

0

评论由:ataggart 发布

补丁已更新到当前的CLJ-445补丁。

0

评论由:klauern 发布

这个工单是否处于挂起状态?我发现自己经常输入 {{(.someCall arg1 arg2 (into-array SomeType nil))}} 以获得正确的调用方法。这个工单看起来可以解决我经常使用的那个额外的 {{into-array}} 参数。

0

评论由:jafingerhut 发布

2012年10月29日上传的 fixbug445.diff 文件由 Alexander Taggart 于2010年10月23日编写。我将它从旧的 Assembla 工单跟踪系统复制到这里以便更容易访问。不出所料,它无法干净地应用于最新的 master。我不知道更新它的努力有多大,但是根据“更新过时的补丁”部分,只有少数几段适用性不佳。请参阅这里的 JIRA 工作流程页面上的“Updating stale patches”部分:http://dev.clojure.org/display/design/JIRA workflow

0

评论由:jafingerhut 发布

唉。删除了附件,因为它是关于CLJ-445的(至少命名为这样)。CLJ-445肯定有一个很长的注释历史,所以如果其中一个或更多的补丁解决了这个问题,那么你可以阅读那里的讨论以了解历史。

我不知道有任何“挂起”状态的票据,除了Rich Hickey在一个评论中明确表示他想要等待一段时间才做出更改的一两个票据。只是有贡献者选择要做的票据和筛选人员选择要筛选的票据。

0

评论者:alexmiller

我非常希望看到对这份票据的更新补丁,该补丁专门解决了varargs问题,而不是基于其他提到的票据和补丁(该补丁优先级较低)。

0

评论者:ragge

我在这方面试了试,附上一个初始补丁,其中一些内容我不太确定/满意,所以欢迎反馈。

该补丁采取了以下方法

  1. 教{{Reflector/getMethods}}如何找到匹配的varargs方法。除了当前约束外,如果方法是一个varargs方法,并且该方法的arity比请求的arity多一个,则它也可以匹配。这意味着它是一个我们可以调用的varargs方法,但用户没有提供varargs参数。
  2. 在{{MethodExpr/emitTypedArgs}}中,我们处理方法调用时比提供的参数多一个参数的情况。在这种情况下应该发生的唯一情况是该方法是varargs方法且最后一个参数没有提供。在这种情况下,我们将新的空对象数组推入堆栈。

我对第二部分的实现不太确定。它可能会在未来打开一些难以理解的错误。一个选择是将更加谨慎,并确保它是最后一个参数,例如,或者甚至是传递{{Method}}对象(或varargs标志)以使我们“知道”我们期望和需要做什么。

0

评论者:ragge

我发现我的补丁缺少两个重要的情况;Reflector中的接口处理和多个匹配方法的处理。我还会查看这一点,但仍然欢迎对{{MethodExpr/emitTypedArgs}}中的方法提出反馈。

0

评论者:alexmiller

我赞成使用isVarArg()来显式处理这种情况,而不是猜测我们是否处于这种状态。我们应该检查调用变长参数方法的参数过多、过少等行为(并在需要的地方添加测试),并且也要确保非变长参数的情况没有改变行为。

此外,请注意,作为一个通用规则,现有的AOT编译后的代码可能会依赖于调用public Reflector方法,因此如果你更改public Reflector方法的签名,你应该保留一个具有旧个数和某些默认行为以支持向后兼容性的版本。

0

评论者:gshayban

编译器实现的任何额外逻辑都需要区分

`

public static class MultipleVarargMethods {
    public static void m(String... args) {}
    public static void m(String arg1, String... args) {}
}

`

我认为这在大致上是不可能的,否则会破坏代码。

与其省略变长参数,不如在不进行繁琐的数组构造的情况下处理它们。一个替代方案是引入新的显式语法糖,你必须选择启用它

(Whatever/varargs a b c ... x y z)

其中...或类似的内容将在编译器中的StaticMethodExpr或InstanceMethodExpr中得以理解,并且可以设置为类型提示以解决歧义。这将不会是一个破坏性的变更。

0

评论者:pbwolf

如果javac能够在调用者不提供"..."分区的帮助下区分方法,Clojure也应该是如此。(但在特定的"MultipleVarargMethods"类中,javac无法区分)

`
public class MultipleVarargMethods {

public static void m(String... args) {}
public static void m(String arg1, String... args) {}
public static void main(String [] args) {
    m("bankruptcy");
    m("bankruptcy","in","progress");
}

}

MultipleVarargMethods.java:5: 错误:对m的引用模糊

    m("bankruptcy");
    ^

MultipleVarargMethods类中的两个方法m(String...)和m(String,String...)都匹配方法m
MultipleVarargMethods.java:6: 错误:对m的引用模糊

    m("bankruptcy","in","progress");
    ^

MultipleVarargMethods类中的两个方法m(String...)和m(String,String...)都匹配方法m
2个错误
`

)

0
...