阅读 820

[译] 一个简单方式教你记住Kotlin的形参和实参

翻译说明:

原标题: Parameters and Arguments: An Easy Way to Remember the Difference

原文地址: typealias.com/guides/para…

原文作者: Dave Leeds

简述(俗称扯皮):

最近在深入研究Kotlin中的泛型语法,发现它和Java中的泛型有着很大不同,在语法上Kotlin的泛型也会比Java中的使用起来更安全。但是发现Kotlin泛型一时间冒出了很多的名词术语,什么协变、逆变、不变、星投影啊;什么实化参数、类型形参、类型实参啊,什么类、类型、子类、子类型、超类型弄得是一脸懵逼. 不过还好基本都弄懂了,于是乎想准备一系列关于Kotlin中泛型的博客来记录我的坎坷,希望能有所帮助。

以下是我之前的一些关于Kotlin的文章,如感兴趣欢迎查看:

翻译系列:

原创系列:

实战系列:

今天是一篇简单的博客翻译作为Kotlin泛型语法系列开场白:

进入正题(开始翻译啦...)

你是否曾经很难记住形参和实参的区别,今天这篇文章就是为了量身打造的。理清它们之间的区别可以帮助你更好地深入理解函数,此外甚至可以更多帮助你理解泛型。

形式参数与实际参数

  • 定义在里面就是形式参数(形参)
  • 定义在外面就是实际参数(实参)

回忆两者之间的差异的最简单的简单的方法就是将arugment单词与outside单词关联起来,记住这句话

“Take your argument outside!

这里有我画的一张卡通图帮你去记住它:

有关更多说明,让我们看一下函数和泛型类的示例。

函数中的形参与实参

这是一个对整数进行平方的简单函数。将传递哪些数据?只是我们想要平方的数字。

fun square(number: Int): Int {
    return number * number
}
复制代码

在这个函数的定义里面,我们说number就是一个形式参数

现在已经定义好了我们的函数,当我们调用它时,会将一些数据传递给这个函数。

val radius = 5
val area = Math.PI * square(radius)
复制代码

这里,在函数定义的外面,我们说radius是square函数的实际参数

泛型中的形参与实参

泛型类是具有一种或多种类型的类。例如,这里有个非常简单的Box类,它只包含其他一些对象。

class Box<T>(var item: T)
复制代码

这里,在Box类定义的里面,我们说T是一个类型形参

使用这个类十分简单,我们只需要调用它的构造器,并传入一些符合正确类型的数据进去即可。

val box = Box<String>("Hello")
复制代码

这里,在Box类定义的外面,我们使用String类型实参去构造它。

事实上,Kotlin做了一些智能的类型推导,所以我们甚至不必明确指定它:

val box = Box("Hello")
复制代码

在这种情况下,它仍然有一个String类型的类型实参。它只是隐含在我们传递给构造函数的“Hello”实际参数的类型中而已。

总结

再次说明下,在函数和泛型类/接口两种情况下,结论是:

  • 形参 - 在定义里面
  • 实参 - 在定义外面

读者有话说

其实这篇文章目的很简单就是帮助理解一个问题:Kotlin中泛型形参和实参区别。因为这两个术语将会在后续泛型文章中被多次提到。所以如果不提前弄懂这些名词概念,后面一些深入的东西理解起来会非常吃力的。我补充几点:

  • 第一: 为了验证一下理论,我们一起分析下下面两个例子:
class StringList: List<String>{
    ...
}
复制代码

对于以上例子很好理解,StringList类实现List接口,提供了具体的类型实参: String,可以看到String明显是在List接口定义的外面,所以它就是类型实参

class ArrayList<T>: List<T>{
    ...
}
复制代码

关于这个例子,大家看看怎么分析呢?? 实际上很简单就按照这篇文章作者说的那样抓住问题关键点: 类型参数在类或接口定义外面还是里面,里面就是形参,外面就是实参

所以,这里例子很容易分析出这个T是List接口的类型实参,而不一样的是这个T同时还是ArrayList这个类的类型形参。ArrayList类中定义了自己的类型形参T,并把指定为父类(List接口)类型的实参。在Kotlin的泛型中有这样规定: 如果一个类继承泛型类(或者实现了泛型接口),就必须为基础类型的泛型形参指定一个泛型实参。它可以是具体的类型或者另一个类型形参。所以你会发现ArrayList 中的T和List中的T实际上有所不一样的,就是类型形参和类型实参的区别。

  • 第二、初学者很容易走进一个误区,认为类似T,K,V这种没有具体意义的类型就是类型形参,而像String,Int这种具体有意义的类型就是类型实参。这种理解是错误,总之可以按照原文作者那样理解。
  • 第三,在Kotlin中规定所有的泛型实参需要显示的声明,要么能被编译器智能推导出来。也就是不能像Java中那样直接一个List(Java中原生态类型)就行,不用指定泛型实参,这种情况在Kotlin中不允许的,编译器就会报错。所以不得不夸下Kotlin了,它语法上非常严谨和明确,不能含糊,在定义和声明就必须明确下来。
  • 第四,泛型函数中也有自己的类型形参,在每次函数执行调用时类型形参会被替换成类型实参,有点函数中形参和实参。

这是泛型系列文章简单的开场白,下面将会继续深入Kotlin泛型相关内容,例如泛型擦除以及实化类型参数,泛型协变,逆变,星投影。欢迎继续关注~~

欢迎关注Kotlin开发者联盟,这里有最新Kotlin技术文章,每周会不定期翻译一篇Kotlin国外技术文章。如果你也喜欢Kotlin,欢迎加入我们~~~

关注下面的标签,发现更多相似文章
评论