为什么Kotlin没有显式输入?

Nin*_*ska 6 java android type-inference kotlin

我对此感到很好奇,为什么Kotlin设计师会认为这是删除Kotlin中显式输入的好主意?

对我来说,显式键入并不是用Java(或任何其他强类型语言)编写的“痛点”:所有IDE都可以帮助我自动键入变量。

它增加了对代码的理解(这就是为什么我不喜欢弱类型的语言,我不知道我正在处理哪种变量的原因)。

另外,这是我的主要问题,它使代码更易于出错。

例子:
Java:很容易识别为字符串,一切都很好

String myPrice = someRepository.getPrice(); // Returns a String
myTextView.setText(myPrice); 
Run Code Online (Sandbox Code Playgroud)

Java:很容易被识别为int,带有代码味道 setText()

int myPrice = someRepository.getPrice(); // Returns an int, code smell !!
myTextView.setText(String.valueOf(myPrice)); // Problem avoided
Run Code Online (Sandbox Code Playgroud)

科特林:????

val myPrice = someRepository.getPrice(); // What does it return ?
myTextView.setText(myPrice); // Possible hidden bug with setText(@StringRes int) instead of setText(String) !!
Run Code Online (Sandbox Code Playgroud)

在Kotlin imo中,没有明确的键入是Kotlin的最大缺点。我试图了解这种设计选择。

我并不是真正在寻找“补丁”来修复示例/避免出现代码的味道,我试图了解删除显式键入背后的主要原因。它必须不仅仅是“减少键入/更易于阅读”。它只删除了几个字符(一个字符仍然必须写val/ var),并且在Kotlin中进行显式键入仍然会添加一些字符。

在我看来,没有显式类型的静态类型是处理隐藏的bug /意大利面条错误的最坏情况:如果一个类(例如“存储库”)更改了它的返回类型(例如从Stringint)。使用显式输入时,编译将在调用“存储库”的类上失败。如果没有显式键入,则编译可能不会失败,并且错误类型的变量可能会“遍历”类,并由于其类型而改变类的行为。这是危险的,未被发现。

修复很简单; 明确键入变量。但是,这就是我们所说的Kotlin,是一种面向代码高尔夫球手的语言:人们不会显式地键入变量,因为在kotlin中,这样做比用turtle-java花费更多的时间。kes!

Gho*_*ica 15

首先:Kotlin具有静态类型。编译器确切知道哪种类型到达或到达哪里。而且您总是可以将其写下来,例如

fun sum(a: Int, b: Int): Int {
  val c: Int = 1
Run Code Online (Sandbox Code Playgroud)

关键是:您可以编写许多代码,这些代码仅依赖于您所做的任何事情都是静态类型的,而且类型也经过检查的事实!

当您只需要看待a + b什么时,您是否真的需要知道要添加两个双精度数还是两个int或两个long ?

最后,这是关于平衡不同的需求。省略类型可能会有所帮助:减少人类读者需要阅读和理解的代码。

当然:如果编写代码使人们不断地向他们的IDE寻求IDE来告诉他们实际的,推断的类型,那么您就将有用的功能变成了问题!

真正的答案是:这取决于。我到过很多代码评论中,C ++人士讨论了auto关键字的使用。在很多情况下,使用auto确实会使代码更易于阅读和理解,因为您可以专注于“变量会发生什么”,而不是花一分钟时间看一下它的声明,而是试图理解它的类型。但是,也有一些偶然的例子auto完全相反,并且“完全键入”声明更易于遵循。

并得到了OP的评论:首先,您应该知道自己在做什么。含义:编写代码时,您不仅会调用在某个对象上找到的“任何”方法。您必须调用方法。您最好知道它的作用,以及它的收益。我同意,当有人匆忙时,您迅速进行var-assign,然后再传递,可能会导致错误。但是对于每种var有助于创建错误的情况,可能会发生10个事件,有助于编写易于阅读的代码。就像说的那样:生活就是平衡。

最后:语言不应无缘无故地添加功能。Kotlin员工正在仔细权衡他们添加的功能。他们没有添加类型推断,因为C ++有。他们之所以添加它,是因为他们仔细研究了其他语言,并发现将其作为语言的一部分非常有用。任何语言功能都可能被滥用。它总是由程序员编写的代码,很容易阅读和理解。而且,当您的方法的签名不明确时,仅“读取”它们的名称并不能告诉您问题所在,然后将其归咎于方法名称而不是类型推断!

  • 当人们甚至不知道变量是什么类型时,他们如何能够关注“变量会发生什么”,因此,他们如何才能正确地与变量交互? (2认同)

Ale*_*nov 6

引用Java的Local-Variable Type Inference JEP

在像这样的通话链中:

int maxWeight = blocks.stream()
                    .filter(b -> b.getColor() == BLUE)
                    .mapToInt(Block::getWeight)
                    .max();
Run Code Online (Sandbox Code Playgroud)

没有人担心(甚至没有注意到)中间类型Stream<Block>IntStream以及lambda形式的类型b并未明确出现在源代码中。

你烦了吗?

如果一个类(例如说“存储库”)更改了它的返回类型(例如,从String到int)。使用显式输入时,编译将在调用“存储库”的类上失败。

如果您setText的示例中有重载,则

Repository repository = ...;
myTextView.setText(repository.getFormerlyStringNowInt());
Run Code Online (Sandbox Code Playgroud)

没有类型推断也不会失败。要使其失败,您的代码标准必须要求将每个操作的结果分配给局部变量,如

Stream<Block> stream1 = blocks.stream();
Predicate<Block> pred = b -> { 
    Color c = b.getColor();
    return c == BLUE;
};
Stream<Block> stream2 = stream1.filter(pred);
ToIntFunction<Block> getWeight = Block::getWeight;
IntStream stream3 = stream2.mapToInt(getWeight);
int maxWeight = stream3.max();
Run Code Online (Sandbox Code Playgroud)

此时,仅由于降低的可读性和偶然使用错误的变量的机会,您就使bug变得更容易。

最后,Kotlin并不是凭空创造的:设计人员可以看到,当C#在2007年引入局部类型推断时,它并没有导致重大问题。或者他们可以看看Scala,它从2004年开始就拥有它。它有(并且有)大量的用户抱怨,但是本地类型推断不是其中之一。