在回答另一个问题时,我遇到了一些我没想到的Clojure的变量arity函数args:
user=> (defn wtf [& more] (println (type more)) :ok)
#'user/wtf
;; 1)
user=> (wtf 1 2 3 4)
clojure.lang.ArraySeq
:ok
;; 2)
user=> (let [x (wtf 1 2 3 4)] x)
clojure.lang.ArraySeq
:ok
;; 3)
user=> (def x (wtf 1 2 3 4))
clojure.lang.PersistentVector$ChunkedSeq
#'user/x
user=> x
:ok
Run Code Online (Sandbox Code Playgroud)
为什么ArraySeq1)和2)中的类型,但PersistentVector$ChunkedSeq在3)?
C#/ .NET通过传递Array类型by-reference来具有可变参数函数参数(与C/C++相反,它只是将所有值直接放在堆栈上,无论好坏).
在C#世界中,这有一个很好的优点,允许您使用'raw'参数或可重用的数组实例调用相同的函数:
CultureInfo c = CultureInfo.InvariantCulture;
String formatted0 = String.Format( c, "{0} {1} {2}", 1, 2, 3 );
Int32 third = 3;
String formatted0 = String.Format( c, "{0} {1} {2}", 1, 2, third );
Object[] values = new Object[] { 1, 2, 3 };
String formatted1 = String.Format( c, "{0} {1} {2}", values );
Run Code Online (Sandbox Code Playgroud)
这意味着生成的CIL相当于:
String formatted0 = String.Format( c, "{0} {1} {2}", new Object[] { 1, 2, 3 } );
Int32 third = 3;
String formatted0 …Run Code Online (Sandbox Code Playgroud) 这个小程序
public class Client {
public static void main(String[] args) throws Exception {
Arrays.asList(null);
}
}
Run Code Online (Sandbox Code Playgroud)
抛出一个NullPointerException。
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
at java.base/java.util.Arrays$ArrayList.<init>(Arrays.java:4322)
at java.base/java.util.Arrays.asList(Arrays.java:4309)
at org.example.Client.main(Client.java:10)
Run Code Online (Sandbox Code Playgroud)
但是,该程序
public static void main(String[] args) throws Exception {
Arrays.asList(returnNull());
}
private static Object returnNull(){
return null;
}
Run Code Online (Sandbox Code Playgroud)
才不是。他们为什么表现不同?
可能重复:
是否有使用带参考参数的varargs
嗨,我有一个varargs的问题.看看我的代码(Microsoft Visual Studio 2005或2008).
#include <stdarg.h>
struct Test { int a; };
void T1(int n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*);
va_end(args);
}
void T2(Test n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*);
va_end(args);
}
void T3(const Test& n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*); // p corrupt!!
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[]) {
const Test t;
T1(1, "Test1");
T2(t, "Test2");
T3(t, …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写可以使用任意数量的整数和字符串调用的Java函数的原型:
myMethod(1, 2, 3, "Hello", "World"); // Valid call
myMethod(4, "foo", "bar", "foobar"); // Valid call
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望以任何顺序(并且可能混合)给出整数和字符串:
myMethod(1, "Hello", 2, "World", 3); // Valid call
Run Code Online (Sandbox Code Playgroud)
我想过使用varargs,但原型中只能有一个.我的另一个想法是使用以下原型:
public void myMethod(Object ... objs) { [...] }
Run Code Online (Sandbox Code Playgroud)
...但我觉得如果用预期类型以外的东西调用它应该有一个编译错误.当然,instanceof可以执行运行时检查(),但这不是一个非常优雅的解决方案,不是吗?
你会怎么做?
在这份文件中,作者说
只有POD类型可以作为省略号"..."的参数,而std :: string不是POD类型.
我理解为这个Passing NON-POD type to Variadic function is undefined behavior.这样对吗?
虽然,他是说C/C++标准吗?我试图在n3242 C++规范中找到它.但找不到.
我想知道我的理解是正确的,这是一个标准.
据我所知,Scala标准库中的特征类似于List或者Seq是在Scala标准库中实现的,而不是语言本身的一部分.
但有一件事我不明白:一个有类似可变函数的语法
def foo(args: String*) = ...
Run Code Online (Sandbox Code Playgroud)
在内部,一个人可以访问args,它将是一个Seq.
我不清楚是否:
Seq 被认为是一种特殊的数据结构,足以作为语言的一部分出现,或者*这里的表示法是一种更通用语法的特殊情况,它设法避免对具体数据结构接口的任何引用.有谁知道哪一个是正确的解释?
Scala提供了一个生成Java varargs转发器方法的@varargs注释,可以编写如下内容:
import scala.annotation.varargs
class Foo {
@varargs def foo(args: String*): Unit = {
args.foreach(println)
}
}
Run Code Online (Sandbox Code Playgroud)
然后从Java调用此方法而无需创建scala.Seq:
Foo foo = new Foo();
foo.foo("a", "b");
Run Code Online (Sandbox Code Playgroud)
这很不错.
不幸的是,当方法是抽象的时,似乎没有发生转发部分:
trait Bar {
@varargs def bar(args: String*): Unit
}
class Baz extends Bar {
def bar(args: String*): Unit = {
args.foreach(println)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我们有这个Java代码:
Bar bar = new Baz();
bar.bar("a", "b");
Run Code Online (Sandbox Code Playgroud)
我们得到这个异常(在运行时):
java.lang.AbstractMethodError: Baz.bar([Ljava/lang/String;)V
Run Code Online (Sandbox Code Playgroud)
我们可以用以下方法确认问题javap:
public interface Bar {
public abstract void bar(java.lang.String...);
public abstract void …Run Code Online (Sandbox Code Playgroud) 我正在努力将一个字符串List传递给一个需要参数" String ... "的方法.
有人可以帮帮我吗?
// How to put names into dummyMethod?
List<String> names = getNames();
Run Code Online (Sandbox Code Playgroud)
public void dummyMethod(String... parameter) {
mInnerList.addAll(Arrays.asList(parameter));
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试决定在每次使用参数化的varargs(例如in)时遇到Java堆污染警告时该怎么做
public static <T> LinkedList<T> list(T... elements) {
...
}
Run Code Online (Sandbox Code Playgroud)
在我看来,如果我有信心不在我的方法中使用一些奇怪的演员,我应该@SafeVarargs继续使用并继续前进.但这是正确的,还是我需要更加小心?使用参数化varargs时,是否有明显正确的代码实际上不安全?
阅读有关该主题的内容,我注意到提供的示例非常人为.例如,Java文档显示以下错误方法:
public static void faultyMethod(List<String>... l) {
Object[] objectArray = l; // Valid
objectArray[0] = Arrays.asList(42);
String s = l[0].get(0); // ClassCastException thrown here
}
Run Code Online (Sandbox Code Playgroud)
这是教诲但非常不现实; 有经验的程序员不太可能编写代码来做这样的事情.另一个例子是
Pair<String, String>[] method(Pair<String, String>... lists) {
Object[] objs = lists;
objs[0] = new Pair<String, String>("x", "y");
objs[1] = new Pair<Long, Long>(0L, 0L); // corruption !!!
return lists;
}
Run Code Online (Sandbox Code Playgroud)
这显然是以一种不切实际的方式混合类型.
那么,在参数化的变量下,堆污染会发生更微妙的情况吗?@SafeVarargs如果我没有以丢失输入信息的方式转换变量,或者错误地混合类型,我是否有理由使用?换句话说,我是否有理由将这一警告视为一种不太重要的形式?