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

翻译说明:

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

原文地址: https://typealias.com/guides/parameters-arguments/

原文作者: Dave Leeds

简述(俗称扯皮):

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

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

翻译系列:

  • [译]Kotlin中是应该定义函数还是定义属性?
  • [译]如何在你的Kotlin代码中移除所有的!!(非空断言)
  • [译]掌握Kotlin中的标准库函数: run、with、let、also和apply
  • [译]有关Kotlin类型别名(typealias)你需要知道的一切
  • [译]Kotlin中是应该使用序列(Sequences)还是集合(Lists)?
  • [译]Kotlin中的龟(List)兔(Sequence)赛跑
  • [译]Effective Kotlin系列之考虑使用静态工厂方法替代构造器(一)
  • [译]Effective Kotlin系列之遇到多个构造器参数要考虑使用构建器(二)

原创系列:

  • 有关Kotlin属性代理你需要知道的一切
  • 浅谈Kotlin中的Sequences源码解析
  • 浅谈Kotlin中集合和函数式API完全解析-上篇
  • 浅谈Kotlin语法篇之lambda编译成字节码过程完全解析
  • 浅谈Kotlin语法篇之Lambda表达式完全解析
  • 浅谈Kotlin语法篇之扩展函数
  • 浅谈Kotlin语法篇之顶层函数、中缀调用、解构声明
  • 浅谈Kotlin语法篇之如何让函数更好地调用
  • 浅谈Kotlin语法篇之变量和常量
  • 浅谈Kotlin语法篇之基础语法

实战系列:

  • 用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)
  • 用Kotlin撸一个图片压缩插件-插件基础篇(二)
  • 用Kotlin撸一个图片压缩插件-实战篇(三)
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用

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

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

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

形式参数与实际参数

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

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

“Take your argument outside!

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

[译] 一个简单方式教你记住Kotlin的形参和实参_第1张图片

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

函数中的形参与实参

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

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,欢迎加入我们~~~

Kotlin系列文章,欢迎查看:

Kotlin邂逅设计模式系列:

  • 当Kotlin完美邂逅设计模式之单例模式(一)

数据结构与算法系列:

  • 每周一算法之二分查找(Kotlin描述)

翻译系列:

  • [译] Kotlin中关于Companion Object的那些事
  • [译]记一次Kotlin官方文档翻译的PR(内联类)
  • [译]Kotlin中内联类的自动装箱和高性能探索(二)
  • [译]Kotlin中内联类(inline class)完全解析(一)
  • [译]Kotlin的独门秘籍Reified实化类型参数(上篇)
  • [译]Kotlin泛型中何时该用类型形参约束?
  • [译] 一个简单方式教你记住Kotlin的形参和实参
  • [译]Kotlin中是应该定义函数还是定义属性?
  • [译]如何在你的Kotlin代码中移除所有的!!(非空断言)
  • [译]掌握Kotlin中的标准库函数: run、with、let、also和apply
  • [译]有关Kotlin类型别名(typealias)你需要知道的一切
  • [译]Kotlin中是应该使用序列(Sequences)还是集合(Lists)?
  • [译]Kotlin中的龟(List)兔(Sequence)赛跑

原创系列:

  • 教你如何完全解析Kotlin中的类型系统
  • 如何让你的回调更具Kotlin风味
  • Jetbrains开发者日见闻(三)之Kotlin1.3新特性(inline class篇)
  • JetBrains开发者日见闻(二)之Kotlin1.3的新特性(Contract契约与协程篇)
  • JetBrains开发者日见闻(一)之Kotlin/Native 尝鲜篇
  • 教你如何攻克Kotlin中泛型型变的难点(实践篇)
  • 教你如何攻克Kotlin中泛型型变的难点(下篇)
  • 教你如何攻克Kotlin中泛型型变的难点(上篇)
  • Kotlin的独门秘籍Reified实化类型参数(下篇)
  • 有关Kotlin属性代理你需要知道的一切
  • 浅谈Kotlin中的Sequences源码解析
  • 浅谈Kotlin中集合和函数式API完全解析-上篇
  • 浅谈Kotlin语法篇之lambda编译成字节码过程完全解析
  • 浅谈Kotlin语法篇之Lambda表达式完全解析
  • 浅谈Kotlin语法篇之扩展函数
  • 浅谈Kotlin语法篇之顶层函数、中缀调用、解构声明
  • 浅谈Kotlin语法篇之如何让函数更好地调用
  • 浅谈Kotlin语法篇之变量和常量
  • 浅谈Kotlin语法篇之基础语法

Effective Kotlin翻译系列

  • [译]Effective Kotlin系列之考虑使用原始类型的数组优化性能(五)
  • [译]Effective Kotlin系列之使用Sequence来优化集合的操作(四)
  • [译]Effective Kotlin系列之探索高阶函数中inline修饰符(三)
  • [译]Effective Kotlin系列之遇到多个构造器参数要考虑使用构建器(二)
  • [译]Effective Kotlin系列之考虑使用静态工厂方法替代构造器(一)

实战系列:

  • 用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)
  • 用Kotlin撸一个图片压缩插件-插件基础篇(二)
  • 用Kotlin撸一个图片压缩插件-实战篇(三)
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用

你可能感兴趣的:(Kotlin,Kotlin,泛型,Java,类型形参,类型实参)