mian方法例子

fun main(){
println("Hello World");
}

变量

val定义只读变量
var定义可变变量

顶层变量-定义在main函数外面的变量,类似Java中的静态变量,但是没有跟类强关联,可直接调用,不用通过类名去调用

val PI = 3.14; // top level变量  
fun main() {  
    val popcorn = 5  // 不可变变量
    val hotdogs = 10  
    var customer = 10  //可变变量
    customer = 8  
    println(customer)  
    println(PI)  
}

字符串模板

字符串模板表达式以$开始,如果需要计算可以使用{}

var customer = 10;
println("Customer: $customer");  
println("Customer: ${customer + 1}");

基本数据类型

kotlin的每个变量和数据结构都有类型。Kotlin编译器会通过类型推断来确定变量的类型
总共有13种基本数据类型

整数

Byte/Short/Int/Long

val year: Int = 20;
无符号整数

UByte/UShort/UInt/ULong

val scope: UInt = 100u;
浮点数

Float/Double

val tmp: Float = 1.0f
val tmp2: Double = 2.0
//val tmp2: Double = 2.0d 不能加d
布尔值

Boolean

val flag: Boolean = true;
字符

Char

val c: Char = 'a'
字符串
val str: String = "Hello"
声明未初始化变量

必须用":"指定类型,否则编译报错
必须在使用之前赋值,否则编译报错

val a: Int
a = 5

集合

有三种集合类型:List/Set/Map
List:有序集合
Set:独特的无序集合
Map:键值对,键唯一,每个键只映射到一个值
每种集合类型都是可变的和只读的

List

按添加顺序存储,允许重复项

只读列表用listOf函数创建
可变列表用mutableListOf函数创建

val readOnlyShapes = listOf("triangle", "square", "circle")

val mutableShapes: MutableList<String> = mutableListOf("triangle", "square", "circle")

//为防止不期望的改变,可以将可变列表转换为可读不可变的列表,类型转换
//转变的原理是通过接口继承关系隐藏了Mutable集合的可变能力,其实底层还是一个可变集合对象,能通过原来的引用去调用它的可变方法。而反过来List->Mutable则不行,原因是List是Mutable的父接口,不可变转可变不安全,List本质是可不变的,假如转了之后没有可变的能力
val shapesLocked: List<String> = mutableShapes 

List是有序的,可用索引下标访问

println(readOnlyShapes[0])
println("${readOnlyShapes[0]}")

//获取列表的第一个元素
readOnlyShapes.first()
//获取列表的最后一个元素
readOnlyShapes.last()
//统计列表中元素数量
readOnlyShapes.count()
//判断某个元素是否存在列表中
println("a" in readOnlyShapes)

//可变列表添加和删除元素
mutableShapes.add("a")   
mutableShapes.remove("a")
Set

无序且不可重复

//创建只读Set
val readOnlyFruits = setOf("apple", "banana", "orange")  
//创建可变Set
val mutableFruits = mutableSetOf("apple", "banana", "orange")  
//显示声明Set内元素类型
val mutableFruits2: MutableSet<String> = mutableSetOf("apple", "banana", "orange")

//Set同样可以从可变转为只读
val readOnlyFruits3: Set<String> = mutableFruits2

//同样用in判断元素是否存在, 还有count add remove等方法

Map
映射,键值对

//创建只读映射
val map = mapOf("apple" to "banana", "orange" to "apple")  
//创建可变映射
val map2 = mutableMapOf("apple" to "banana", "orange" to "apple")
//显式声明Map键值对类型
val map3: MutableMap<String, Int> = mutableMapOf("apple" to 1, "orange" to 2)
//可变Map转换为只读Map
val map4: Map<String, Int> = map3
//用键取值
println(map3["apple"])
//如果键不存在,返回null,但是没报空指针异常
println(map3["apple2"])
//可用索引访问[]符向Map中添加键值
map3["abc"] = 100
//移除用remove函数
map3.remove()
//count统计键值对数量
println(map3["abc"])
//containskey判断某个键是否存在Map中
map3.containsKey("abc")
//获取Map的键集合或者值集合,直接.keys或者.values属性即可
println(map3.keys)  
println(map3.values)
//用in判断键是否在映射中
"apple" in map3
"apple" in map3.keys
//用in判断值是否在映射中
100 in map3.values


条件表达式

if和when

推荐使用when

var num: Int  
val check = true  
if(check) {  
    num = 1  
}else{  
    num = 0  
}  
println(num)

Kotlin中没有三元运算符,但可用if表示

if(a > b) a else b

当有多个分支时使用when

val name3 = "Java"  
when (name3) {  
    "Java" -> println("gun")  
    "Kotlin" -> println("coming")  
    else -> println("unknown")  
}
//检查到第一个满足条件的分支就执行,并且跳过后续的分支,类似Java中带break的switch

//when可以返回值
val name3 = "Java"  
val result = when (name3) {  
    "Java" -> "gun"  
    "Kotlin" -> "coming"  
    else -> "unknown"  
}  
  
println(result)

//可以没有主语(参数)
val result = when {  
    "Java" == name3 -> "gun"  
    "Kotlin" == name3 -> "coming"  
    //注意else也要加->
    else -> "unknown" 
}

注意:when下各个分支要统一返回类型,虽然在混合String和Int返回时Kotlin的类型推导会把when表达式的返回值类型判断为它们的父类Any,从而没有编译错误,但是混合类型返回代码可读性差,且不安全

范围

1…4相当于1,2,3,4
1…<4相当于1,2,3 左闭右开
4 downTo 相当于4,3,2,1 逆序
1…5 step 2 相当于1,3,5 自定义步长为2

Char也可以用区间,比如:
‘a’…‘d’相当于’a’,‘b’,‘c’,‘d’
‘z’ downTo ‘s’ step 2 相当于’z’ ,‘x’, ‘v’,‘t’

循环

for
for (number in 1..5){  
    print(number)  
}
while
var cakesEaten = 0  
while(cakesEaten < 5){  
    println("eat $cakesEaten")  
    cakesEaten++;  
}

do{
println("eat $cakesEaten")  
    cakesEaten++;  
}while(cakesEaten < 10)

函数

Kotlin函数的特点:
参数必须有类型,用逗号分隔
返回类型写在函数的()之后,用冒号分隔
关键字return用于推出函数或者返回某个值

fun sum(a: Int, b: Int): Int {  
    return a + b  
}
命名参数

在传参时指定参数名,可以按随意顺序传参

fun main() {  
    printMessageWithPrefix(prefix = "Sean", message = "Hello World")  
}
fun printMessageWithPrefix(message: String, prefix: String) {  
    println("[$prefix] $message")  
}
默认参数值

在函数定义时可以定义默认值

fun printMessageWithPrefix(message: String, prefix: String = "Info") {
    println("[$prefix] $message")
}

无返回值的函数
如果函数没有返回值,其实返回的类型是Unit

fun printMessage(message: String){  
    println(message)  
}
单表达式函数

省略{},用=号来声明函数体,省略返回类型

fun sum(a: Int, b: Int) = a + b

如果使用{}则必须声明返回类型,除了Unit外

提前返回

用return提前返回值,跟Java一样

lambda表达式

    val upperCaseString = { text: String -> text.uppercase() }
    println(upperCaseString("hello"))

->之前是参数
->之后是函数体
使用=把函数表达式赋值给了变量upperCaseString

lambda传递给另一个函数

Kotlin中lambda对函数的最后一个参数是lambda表达式的优化:可以将lambda表达式拿出()外,如果同时这个函数没有其他参数,可以省略掉()

val positives = numbers.filter { x -> x > 0 }

.map函数,用来转换集合中的元素
"it"是Kotlin提供的隐式参数,在函数只有一个参数的时候可以使用它,不能自定义名称

val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  
val doubleD = numbers.map { it * 2 }  
val tripleD = numbers.map { it * 3 }  
println(doubleD)  
println(tripleD)
函数类型

“函数的形状”
包括参数类型,返回值类型,能执行的操作
函数类型的语法有:

  • 每个参数的类型写在括号 () 内,并用逗号 , 分隔。
  • 在 -> 之后的返回类型。
    例如:(String) -> String
val upperCaseString: (String) -> String = { str -> str.uppercase() }

你必须要么在 lambda 表达式中声明参数和返回类型,要么作为函数类型声明。否则,编译器将无法知道你的 lambda 表达式的类型。

从函数中返回

lambda表达式可以从函数中返回,前提是必须声明表达式的类型。
以下定义了一个返回函数的函数toSeconds(time: String): (Int) -> Int

fun toSeconds(time: String): (Int) -> Int = when (time){  
    "hour" -> {value -> value * 60 * 60}  
    "minute" -> {value -> value * 60}  
    "second" -> {value -> value}  
    else -> {value -> value}  
}
/**定义了一个toSeconds函数,这个函数接收一个String参数time,根据这个参数time动态的返回函数类型为(Int) -> Int的函数
1.为什么不用val?因为语义上不符合"动态生成转换逻辑的函数",val更加趋向固定值
2.为什么when后的time不需要声明String类型?因为前面已经声明过了,Kotlin不允许这种冗余代码,而且kotlin会根据when的表达式分支条件去推断这个主语time的类型
3.所谓的返回的函数,其实是lambda表达式,需要用{}包起来
**/

fun main() {  
    val minutes = listOf(10, 20, 30, 40, 50)  
    val sum = minutes.sumOf(toSeconds("minute"))  
    println(sum)  
}  
单独调用

lambda可以在{}后面加()直接调用,()内可以传值

println({text: String -> text.uppercase()}("hello world!"))
尾随lambda

如果lambdad表达式没有参数,可以省略括号()
如果lambda是作为函数的最后一个参数传递,那么可以把lambda放在括号()外面

println(listOf(1, 2, 3).fold(0){x, item -> x + item})
//fold是一个非常灵活的函数,主要用来做累加,拼接字符串的工作,fold意思为折叠,将集合中的元素折叠到初始值initial上,然后返回,使用了泛型,初始值与返回值的类型可以不同,比reduce函数灵活

class Customer
属性

在括号()中声明,括号内的内容称为类头部

class Customer(val name: String, val age: Int)

在花括号{}中声明,需要初始值

class Customer(val name: String, val age: Int) {  
    val id: Int = 0  
}

可以使用尾随逗号

class Customer(val name: String,   
               val age: Int,  
               val age2: Int,  
               val age3: Int,  
    ) {  
    val id: Int = 0  
}
创建实例

默认情况下Kotlin会自动创建一个包含类头部声明的参数的构造函数(无参就生成一个无参构造函数)

class Contact(id: Int, var email: String)
val con = Contact(1, "Sean@qq.com");
访问属性

用"."访问

con.email

println("This is my email ${con.email}")
成员函数
class Contact(id: Int, var email: String){  
    fun sayHello() {  
        println("Hello")  
    }  
}

数据类

数据类是普通类的增强,额外提供了一些成员函数,方便操作数据,减少了模板代码的编写
比如toString()
equals()
==
copy()

data class User(val id: Int, val name: String)

//toString() 普通类没有提供toString()会打印引用,而数据类会打印实例内容
println(user)
//equals() == 比较主构造函数的属性,也就是()内的
//如果包含引用类型成员属性,则会递归的调用引用成员的equals函数继续比较
val user = User(1, "Sean")  
val user2 = User(1, "Sean")  
println(user.equals(user2)) //true

//copy()浅拷贝,user user2依然共享同一份con引用
val user = User(1, "Sean", con)  
println(con)  
val user2 = user.copy()  
println(user2)


空安全

null安全在编译时检查null值的潜在问题
空安全允许以下操作:
1.明确声明程序在何时允许null
2.检查null值
3.使用安全调用可能包含null值的属性和函数
4.如果监测到null值,声明要采取的行动

可空类型

允许声明的类型具有null值
通过在类型声明后显示添加?来声明
默认情况下类型不允许接受空值

var neverNull: String? = "Hello"  
    neverNull = null  
    //neverNull.length 编译报错,不安全,要非空值或者用?.安全调用
检查空值
maybeString != null && maybeString.length > 0
使用安全调用

使用安全调用运算符"?."
如果对象或者其访问的属性为null,则返回null

fun main() {   
    val nullStr = null  
    println(lengthString(nullStr))  
}  
  
fun lengthString(maybeString: String?): Int? = maybeString?.length

//链式安全调用不会抛出错误,而是返回null
person.company?.address?.country

//安全调用符在调用函数之前判断非空,空值则跳过调用,并返回null

使用Elvis运算符

使用Elvis运算符"?:"来给可能存在null值的变量返回一个默认值
左边是表达式或者变量,右边是默认值

println(nullStr?.uppercase() ?: 0)

//配合return可以提前返回
val nonNullValue = value ?: return  // 若 value 为 null,直接返回
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐