介绍Kotlin第一部分(翻译篇)

1、介绍Kotlin

Kotlin是jvm新的开发语言。 谷歌推广Kotlin作为其基于java的Android平台上的第一类语言在五月份。从那之后我就纳闷:这是什么语言?Kotlin已经有好几年了,并且在2016年2月正式在生产系统上运行,语言后的1.0版本,为期一年左右。该语言已经获得很多的赞赏和喜爱。 在这篇文章中我们将涵盖语法等基本构建块,在介绍Kotlin第二部分,我们将接触变量,函数,类,接口和对象。最后,在第三部分,我们来看一看控制流程的几个例子。

1、构建过程

当Kotlin在发展的时候,您的构建过程或多或少和旧的java程序类似。既然您已经熟悉了这些,就没有必要学习新的东西,Gradle/Maven插件:引入Kotlin的构建过程和构建工具。 您可以通过添加Kotlin插件在您的Gradle/Maven中构建脚本。如何做到这一点以及了解更多信息,可以从官方文档Kotlin中找到关于 Maven /Gradle的更多介绍。

2、Kotlin语法

一位伟人曾经说过 talk is cheap, show me the code。 貌似在接触新语言时第一句学到的总是以Hello World开始的。那我们就从这里开始吧。

print("Hello World")

现在,我们已经看到了不同于java的地方。有一些我们熟悉的东西()表示函数调用,但没有分号去结尾,不过看起来也很整齐。好了,下面让我们开始去了解Kotlin吧。

① Kotlin变量

在Kotlin中声明变量有一些不同,我们有关键字valvar,这看起来很相似,但其实有一个重要的区别:

当变量被声明为val时是不可变的(只读),你只能给它分配一次值。变量被声明为var是可变的,可以给它重新分配。

val hello: String = "hello"
val world: String
world = "world"
 
var helloWorld: String = "Hello"
helloWorld = "Hello World"

注意,变量类型如何定义?用冒号分隔。这背后还有一个理由,编译器现在可以决定是否要进行类型推断。这意味着Kotlin比Java有着更强大的类型推断。实际上,你也可以不用声明这些类型编译器也会明白你的意思。

val hell0 = "hi"
val w0rld = "earth"

只有当变量被赋值的时候,该变量的类型才能被推断出来。

② fun

这是什么样的功能呢?由于我们用fun来声明它们,它一定很有趣!哈哈。?

// 无返回值. (也可以这么写 --> fun sayIt (a: String): Unit)
fun sayIt (a: String) { 
    println(a)
}
 
// 有返回值
fun returnIt (returnable: String): String {
    return returnable
}
 
//作为具有推断返回类型和自动返回的单表达式函数
fun returnIt2 (turntable: String) =
    turntable

类型声明遵循相同的模式在这里-它排在后面。在我们的第一个我们不返回任何东西,所以我们可以省略到类型,在这种情况下可以使用Unit。在第二个函数中,我们定义必须返回一个String,使用return语句。最后一个比较令人费解,没有大括号,只是一个等号。这意味着fun是一个表达式,它可以自动返回。

正如你所看到的,在表达式的返回类型上是可选的。可以省略或者留在原位,什么让你更方便(经验法则:长的表达式,把它放在后面。短的表达式,它可以省略)。 Kotlin还引入了可选的命名函数参数的概念。这是很有用的,特别是如果你的函数成长为很多同类型和多种不同参数的时候。

fun optFun(isItFun: Boolean = true, whyIsItFun: String = "Because") = if (isItFun) whyIsItFun else "It's not fun"
 
println(optFun()) // Because
println(optFun(false)) // It’s not fun
println(optFun(whyIsItFun = "It's Summer!")) // It's Summer!

在这个代码块中,我们使用默认值来定义我们的函数参数。当我们这么写的时候,我们可以直接调用该函数的0个、1个或者多个它的参数。

③ 类,接口和对象

与Java一样,Kotlin也具有类和接口。Kotlin团队决定让代码组织更加愉快和语言更加简洁。让我们先了解一下类。

A、类
class SimpleClass
 
// 或者 --> class constructor SimpleClassWithConstructor(val chop: String)
class SimpleClassWithConstructor(val chop: String)

在Kotlin中有很多方式可以创建类。在上面的代码块中给了我们提示:

  • 命名约定以大写字母开头
  • 没有花括号
  • 还有就是在这个例子中没有可见性修改
  • 我们仍然使用class关键字 第二个例子是相似的,但它有一个构造函数。构造函数绑定类的属性(在大多数情况下可以不用关键字constructor,只需要添加类的注解或类的可见性),另一种方式,使得Kotlin更加简洁,当我们实例化这个类时需要给chop赋值。
val lamb = SimpleClassWithConstructor("Hello")

在Kotlin中属性默认是公有的,所以访问该属性的最简单方法:

println(lamb.chop)

这个类不具有任何功能,它只是为我们的数据提供容器。我们可以自定义在里面添加fun类功能。在这种情况下,我们需要使用花括号来包裹我们的声明:

class SimpleClassWithConstructor(val chop: String) {
    fun sayItMate(): String = chop + ", mate"
}

我们可以在这里添加附加的属性,其它类,额外的构造函数或初始化块,我们可以给这些单独分配可见性。

init在Kotlin中做的事情,就是我们通常在Java构造函数中做的事情。如果你想在类中创建一个类,你可以使用inner关键字标记它,以便访问外层类的成员。

class Kenny(val celly: String) {
    lateinit var wheel: CanadianPerson
    val friend: String
 
    init {
        friend = "buddy"
    }
    
    fun initializeWheel (wheeler: String) {
        wheel = CanadianPerson(wheeler)
    }
    
    inner class CanadianPerson(val snipe: String)
 
    // 美元符号使用字符串插值,并使用该属性中定义的toString实现替换$ -prefixed属性名称
    fun sayItCanadianWay(): String = "${wheel.snipe} $celly, $friend"
}
 
val d = Kenny("friend")
d.initializeWheel("I’m not")
print(d.sayItCanadianWay()) // I'm not your friend, buddy

我们通过使用lateinit关键字来告诉编译器,这个属性不为空,即使我们不立即初始化它,这对于不在构造函数中初始化属性很有用。注意,我们的lateinit属性必须是可变的。

init相当于Java中的构造函数块,在那里,我们实例化类时,我们可以执行所需的动作。在这种情况下,我们将一个String赋值给我们的属性。

接下来,我们有一个函数,最终赋值给我们的lateinit属性,实例化一个内部类CanadianPerson,这个内部类只是我们数据的载体。

最后,我们将调用一个函数,这个函数将返回一个String,它使用字符串插值将它们解析并展示出来。

当向类添加其他构造函数时,我们需要调用它们原始的构造函数。

class DoubleTrouble(val str: String){
    constructor(lamb: SimpleClassWithConstructor): this(lamb.chop)
}

我们在类中添加一些简单的功能,除了保存数据什么都不做。

对于这些类型的数据传输对象。Kotlin引入了一个关键字来定义它们:data class。它不同于标准的类,一个data class自动生成equals,hashcode,toString和copy功能。前三个对Java开发者来说是比较熟悉的,第四个是个很好的补充,可以帮助我们从只读数据类创建类似的对象。该copy功能可以这么用:

data class DataClass(val str: String, val num: Int)
val daata = DataClass("Hello", 3)
val peeta = daata.copy(str = "Goodbye")

在这种情况下,我们的peeta包含了num=3和str=“Goodbye”。

我们也可以去获取component数据类对象,这些组件函数通过解构来访问数据类中数据的一种方式。这有利于通过简单的一行调用来获取数据类中的单个属性。

val (str, num) = peeta

有了这个技巧,我们的变量str和num的值分别为"Goodbye"和3。请注意,解构变量的顺序取决于数据类中属性的顺序;这些名字根本不重要。

另外还有两个顶级结构interface和objects。

b、接口

Kotlin中接口与Java中没有什么不同,

interface Sayer {
    val value: String
    fun sayIt(): String
}
 
class SayerClass: Sayer{
    override val value: String = "Hello"
    override fun sayIt(): String = "$value, world"
}
 
println(SayerClass().sayIt()) // Hello, world

如您所见,这与Java非常相似,像Java8一样,Kotlin也可以在接口中提供默认实现,我们可以利用这个特性实现上面一样的效果。

interface Sayer {
    val value: String
    fun sayIt(): String {
        return "$value, world"
    }
}

使用这个我们不必重新实现类中的函数。请注意,override关键字在Kotlin中是强制性的。

c、对象
object SingletonClass{
    fun sayIt(): String = "Hello world"
}
 
class CompaniedClass(val str: String){
    companion object Printer{
        fun sayIt(): String = "Hello world"
    }
}

这是什么呢?你可以使用object关键字创建SingletonClass的单例。

SingletonClass.sayIt() // Hello world

Companied对象是略有不同的,它在一个类中定义,它仍然是一个单例,它可以使用包装类的名称来访问。

CompaniedClass.sayIt() // Hello world

4、控制流程(if,when,for)

a、if

if在Kotlin中的语句或多或少与Java类似,下面我们来看一下它们的不同:

val three = 4
if (three != 3) {
    println("Liar!")
} else{
    println("Good job")
}

这看起来与Java完全相同。但是也略有不同。

val three = 4
val goodOrNot = if(three != 3) {
    "Liar!"
} else{
    "Good job"
}
println(goodOrNot) // Liar!

如果Kotlin语句实际上是表达式,它返回它们块中的最后一个值,

b、when

我们常用的switch-case三元运算符有着同样的命运,它已被Kotlin的when所取代。

when (three) {
    3 -> print("three is three")
    2 -> print("three is two?!?")
    else -> print("I don't know what's going on anymore")
}

正如你所看到的,else替代了default->替换了:字符,关键字break也不再需要,因为when表达式将在第一个为真时停止。这些when表达式有一些有趣的地方,它们可以使用任何类型的表达式进行判断,许多情况下,可以捆绑在一起,而对于数值,可以判断它们的范围。

when (three) {
    3 -> print("three is three")
    1,2 -> print("three is two or one?!?")
    in 4..10 -> print("What? Three can't be between 4 and 10!")
    else -> print("I don't know what's going on anymore")
}

同样的,我们也可以使用when来返回具体值。虽然这看起来有点像if表达式。

val three = 4
val goodOrNot = when {
    three != 3 -> "Liar!"
    else -> "Good job"
}
println(goodOrNot) // Liar!
c、for

for循环相对于Java有挺大的改动。

for (i in 1..10) {
    print(i)
} // 12345678910
 
for (i in 1..10 step 2) {
    print(i)
} // 13579
 
val lst = listOf(1,2,3)
for (i in lst){
    print(i)
} // 123

在第一个例子中我们使用in关键从range中通过..来分配i的值。第二个例子中使用step关键字,表示我们要从这个范围中取其它值。第三个例子循环列表,将listof值打印出来。

总结

以上就是Kotlin语言的基本组成部分,有了这些你就可以使用Kotlin了。希望在看完这篇文章后,你对Kotlin会有自己的看法,在下一章中我们将介绍null safety, lambdas, collections, and types以及Kotlin语言中几个便利的功能

快乐工作,享受编程!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员的碎碎念

Unicode?utf-8?GB2312?

分享一点关于字符编码的来源的知识,是前段时间在廖雪峰老师的python教程里看到的,觉得很通俗易懂,现在复制了过来分享给各位没看过这个教程的朋友们。Unico...

4209
来自专栏一个会写诗的程序员的博客

第4章 类与面向对象编程第4章 类与面向对象编程

在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统等相关的知识。在本章节以及下一章中,我们将一起来学习Kotlin对面向对象编程以及函数式编程的支持...

882
来自专栏Java爬坑系列

【JAVA零基础入门系列】Day8 Java的控制流程

  什么是控制流程?简单来说就是控制程序运行逻辑的,因为程序一般而言不会直接一步运行到底,而是需要加上一些判断,一些循环等等。举个栗子,就好比你准备出门买个苹果...

20810
来自专栏一个会写诗的程序员的博客

第7章 面向对象编程(OOP)

7.2 类与继承 7.2.1 类 7.2.1.1 抽象类 7.2.1.2 接口 7.2.1.3 枚举 7.2.1.4 注解 7.2.1.5 静态类与...

581
来自专栏zhisheng

干货分享:让你分分钟学会 javascript 闭包 一像素

闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它。...

3425
来自专栏MyBlog

Effective.Java 读书笔记(8)关于equals方法

重写equals看上去十分简单对吧,但是我觉得很多时候重写equals可能会招致一些问题,这些问题有时可能会特别严重,当然了不重写不就完事了吗?但是这只适用于那...

764
来自专栏用户2442861的专栏

#define和typedef的用法与区别及面试问题

在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像:

4051
来自专栏逸鹏说道

我为NET狂面试题-基础篇-答案

面向过程: 答案:图片只贴核心代码,完整代码请打开解决项目查看 (答案不唯一,官方答案只供参考,若有错误欢迎提出~) 99乘法表 https://githu...

34113
来自专栏Golang语言社区

interface引发的事件真相

流动的水没有形状,漂流的风找不到踪迹,一切代码都了然于心,我们在写代码的时候,总是有一种思维定式陪伴左右,在对事物做判断的时候,往往这种思维定式会往正向或反向做...

3306
来自专栏liuchengxu

Scala 最佳实践:纯函数

我们所处的是一个命令式编程(imperative programming)的时代,这也是我们为何更喜欢用命令式风格写代码的原因。在我们周围的一切都是可变的。虽然...

761

扫码关注云+社区