在你看来,你遇到过的最令人惊讶、最怪异、最奇怪或最“WTF”的语言特性是什么?

请每个回答只回答一个特征。


当前回答

这是我最喜欢的一个,你可以在Java中不使用main()来执行println。

这将编译和运行,给出println,但也有一个异常(java.lang。NoSuchMethodError:主要)

class Test {
    static {
        System.out.println("I'm printing in Java without main()");
    }
}

其他回答

Modula-2没有elseif或elseif;它有elsif

这并不是一个奇怪的特性,但从类型安全的角度来看,它确实令人恼火:c#中的数组协方差。

class Foo { }
class Bar : Foo { }
class Baz : Foo { }

Foo[] foo = new Bar[1];
foo[0] = new Baz(); // Oh snap!

我相信这是从Java继承而来的(双关语)。

下面的c#代码抛出NullReferenceException而不是打印1:

    static void SomeMethod(string format, params object[] args)
    {
        Console.WriteLine(args.Length);
    }

    static void Main(string[] args)
    {
        SomeMethod("blabla", null, "Ok here"); // print 2
        SomeMethod("blabla", null); // exception
    }

特点:Bash, Korn shell (ksh93)和Z shell都允许使用带或不带美元符号的变量下标数组:

array[index]=$value
array[$index]=$value

加上美元符号,会得到10000的期望值:

unset array
for i in {1..10000}
do
    ((array[$RANDOM%6+1]++))
done
unset total
for count in ${array[@]}
do
    ((total += count))
done
echo $total

陌陌性:如果你从RANDOM中移除美元符号,总数将随机变化,甚至大于10000。

类似地,这将产生3而不是2:

a=1; ((r[a++]++)); echo $a

你不能在这里用美元符号,因为这是赋值运算(a在lhs上)虽然你可以用间接的方法,但是双重求值还是会发生。

原因:对于美元符号,变量展开在算术求值之前执行,因此只执行一次。如果没有美元符号,它将执行两次,一次是计算查找的索引,另一次是计算赋值的索引(因此,实际上,循环中第一步的赋值可能看起来像array[4] = $array[6] + 1,这完全打乱了数组)。

Algol通过名称传递(使用C语法说明):

int a[3] = { 1, 2, 3 };
int i = 1;

void f(int j)
{
    int k;
    k = j;  // k = 2
    i = 0;
    k = j;  // k = 1 (!?!)    
}

int main()
{
    f(a[i]);
}