侧边栏壁纸
博主头像
高压锅里的小白 博主等级

行动起来,活在当下

  • 累计撰写 65 篇文章
  • 累计创建 26 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

变量的声明与使用

高压锅里的小白
2024-12-12 / 0 评论 / 0 点赞 / 4 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

什么是变量

​ ​ 变量,指值可以变的量。变量以非数字的符号来表达,一般用拉丁字母。变量的用处在于能一般化描述指令的方式。结果只能使用真实的值,指令只能应用于某些情况下。变量能够作为某特定种类的值中任何一个的保留器。

​ ​ 比如一个公式 x + 2 = 6 此时 x就是一个变量,变量往往代表着某个值,比如这里的 x就代表的是4这个值。在Kotlin中,我们也可以让变量去代表一个具体的值,并且变量的值是可以发生变化的,在程序中,我们也可以使用变量,并且变量具有类型。

变量的声明与使用

声明变量

要声明一个变量,我们需要使用以下格式:

var [变量名称] : [数据类型]

```kotlin
val [变量名称] : [数据类型]
  1. var/val
    var定义的是可变变量,val定义的是不可变变量。
  2. 数据类型
    就是数据的类型,比如整数就是 Int类型,不同类型的变量可以存储不同的类型的值。
  3. 变量名称
    顾名思义,就像 x一样,这个名称我们可以随便起一个,但是注意要满足以下要求:
    • 标识符可以由大小写字母、数字、下划线(_)和美元符号($)组成,但是不能以数字开头。
    • 变量不能重复定义,大小写敏感,比如A和a就是两个不同的变量。
    • 不能有空格、@、#、+、-、/ 等符号。
    • 应该使用有意义的名称,达到见名知意的目的(一般我们采用英文单词),最好以小写字母开头。
    • 不可以是 true 和 false。
    • 不能与Kotlin语言的关键字或是基本数据类型重名

使用变量

var定义变量

现在我们想要定义一个整数(Int)类型的变量 a,那么就可以这样编写:

fun main() {
    var a : Int
}

但是这个变量一开始没有任何值,比如现在我们要让这个变量表示10,那么就可以将10赋值给这个变量:

fun main() {
    var a : Int = 10
}

不过由于变量在一开始就被赋值为10这个整数,此时类型是确定的,Kotlin的编译器非常聪明,它支持自动推断类型,这里会自动将变量a的类型推断为Int类型,我们可以直接省略掉后面的Int类型:

fun main() {
    var a = 10
}

或者我们可以在使用时再对其进行赋值:

fun main() {
    var a : Int
    a = 10
}

变量的值也可以在中途进行修改:

fun main() {
    var a = 666
    a = 777
    println(a)   //这里打印得到的就是777
}

变量的值也可以直接指定为其他变量的值:

fun main() {
    var a = 10
    var b = a //直接让b等于a,那么a的值就会给到b
    println(b) //这里输出的就是10了
}

我们还可以让变量与数值之间做加减法

fun main() {
    var a = 9   //a初始值为9
    a = a + 1   //a = a + 1也就是将a+1的结果赋值给a,跟数学是一样的,很好理解对吧
    println(a)  //最后得到的结果就是10了
}

val定义常量

对于那些只读的变量,我们可以将其表示为一个常量,使用 val关键字:

fun main() {
    val a = 666 //使用val关键字,表示这是一个常量,常量的值不允许发生修改
}

如果修改val定义的变量,编译时会报错:

```kotlin
fun main() {
    val a = 666
    a = 777;
}

A2u3yx69GbZmStJ.png

val也可以先定义变量不赋值,然后再赋值

fun main() {
    val a: Int
    a = 777;
}

总之,常量只能赋一次值,其他任何情况下都不能修改。

数据类型

​ ​ 前面我们了解了如何创建变量,并进行使用,但是我们知道,不同的数据往往对应着不同的类型,比如整数我们使用的就是Int。

数字类型

整数类型

​ ​ Kotlin提供了一组表示数字的内置类型,对于整数,有四种不同大小的类型,因此,值范围:

类型 大小(位) 最小值 最大值
Byte 8 -128 127
Short 16 -32768 32767
Int 32 -2,147,483,648 (-2^31) 2,147,483,647(2^31-1)
Long 64 -9,223,372,036,854,775,808 (-2^63) 9,223,372,036,854,775,807(2^63 - 1)

​ ​ 默认情况下,我们使用的常量数字都是Int类型,除非它的大小已经超出Int类型能够表示的最大范围,在超出Int类型可以表示的最大范围之后,默认为Long类型:

val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // 我们也可以在数字后面添加大写字母L来表示这是一个Long类型的数值
val oneByte: Byte = 1   //Int类型数据也可以在符合其他类型范围时自动转换

分隔符写法

对于一些比较长的数字,我们可能需要使用类似于分隔符一类的东西来方便我们计数,比如:

银行往往把1000000000这种长数字记为1,000,000,000,这样看起来会更直观

在Kotlin中也可以像这样去编写:

val a = 1_000_000_000

非十进制写法

数字类型不仅可以写成十进制,也可以以十六进制或是二进制表示(Kotlin不支持八进制表示)只需要添加对应的前缀即可

十六进制
val a = 0xAF

因为十六进制中大于等于十的数据没有对应的阿拉伯数字可以表示,所以在计算机中就以ABCDEF来替代这无法表示的6个数字。并且我们需要在数字前面添加0x表示这是16进制的数字

二进制
val a = 0b1001   //0b前缀表示二进制数据,后面的1010对应着十进制的9

无符号整数类型

除了整数类型外,Kotlin还为无符号整数提供以下类型:

  • UByte:一个无符号8位整数,范围从0到255
  • UShort:无符号16位整数,范围从0到65535
  • UInt:一个无符号32位整数,范围从0到2^32 - 1
  • ULong:一个无符号64位整数,范围从0到2^64 - 1

为了使无符号整数更易于使用,Kotlin同样提供了用后缀标记,该后缀表示无符号类型(类似于上面的 Long类型添加L字母)

  • 使用 uU字母作为后缀表示无符号整数。而具体的类型是根据前面变量的类型确定的,如果变量没有提供类型,编译器将根据数字的大小使用 UIntULong

    val b: UByte = 1u  // UByte类型, 由变量提供的类型
    val s: UShort = 1u // UShort类型, 由变量提供的类型
    val l: ULong = 1u  // ULong类型, 由变量提供的类型
    
    val a1 = 42u    // UInt类型,根据数字大小自动推断得到
    val a2 = 0xFFFF_FFFF_FFFFu // ULong类型,根据数字大小自动推断得到
    
  • uLUL可以将文字直接标记为无符号Long类型:

    val a = 1UL // ULong类型,直接使用后缀标记
    

浮点数类型

​ ​ 对于小数来说,Kotlin提供符合IEEE 754标准的浮点类型 FloatDoubleFloat为IEEE 754标准中的单精度数据,而Double位标准中的双精度数据,对于单双精度,本质上就是能够表示的小数位精度,双精度比单精度的小数精度更高。

这些类型的大小不同,并为不同精度的浮点数提供存储:

类型 大小(位) 符号与尾数位数 阶码位数 小数位数
Float 32 24 8 6-7
Double 64 53 11 15-16

我们也可以直接创建小数类型的 DoubleFloat变量,小数部分与整数部分由一个小数点(.)隔开,编译器默认情况下会将所有的小数自动推断为推断 Double类型:

val pi = 3.1415 // 默认推断为Double类型
val one: Double = 1 // 这种写法是错误的,因为1不是小数,无法编译通过
val one: Double = 1.0 // 但是这种写法就是对的,因为这样表示就是小数,即使小数位是0

由于默认是Double类型,如果我们要明确指定值为 Float类型,那么需要添加后缀 fF,并且由于精度问题,如果该值包含超过6-7位小数,则会丢失一部分精度:

val e = 2.7182818284 // Double类型的数值
val e: Float = 2.7182818284f // 这里表示为Float会导致精度折损,得到2.7182817

与其他一些语言不同,Kotlin中的数字类型没有隐式转换的操作,例如,一个 Double类型的变量无法将其值赋值给 Int类型变量:

zwiQaU81LsIujr4.png

如果需要将一个整数转换为小数,我们需要使用对应的函数进行显示类型转换。

数字类型的运算

​ ​ Kotlin支持数学上标准的算术运算集,例如:+-*/% 并且这些运算符都是通过运算符重载实现的具体功能。

​ ​ Kotlin支持运算符重载,运算符重载是一种允许程序员重新定义运算符的语言特性,通过运算符重载,您可以为自定义的类或数据类型定义一些特定操作的行为。

​ ​ 其中加减乘除操作这里就不做介绍了,而%符号用于取余操作,也就是计算前面的数整除后面的数得到的余数:

println(1 + 2)   //计算1加上2的结果
println(2_500_000_000L - 1L)   //计算2500000000减去1的结果
println(3.14 * 2.71)   //计算3.14与2.71的乘积
println(10.0 / 3)   //计算10除以3得到的结果
println(10 / 3)   //10除以3得到的余数为1

以上运算都比较简单,但是注意在除法运算中,只有两个操作数中出现小数,除法的结果才是小数,如果两个操作数都是整数,那么得到的结果也是整数,并且直接丢失小数位(不会四舍五入)

println(5 / 2)    //结果是2,而不是2.5

同样的,除了直接使用字面量来进行运算,我们也可以将定义的变量参与到运算中:

fun main() {
    val a = 10
    println(a / 2)
}

注意,在Kotlin中不同的算数运算符,它们的优先级也不一样:

println(1 + 2 * 3)

在数学中,乘法运算的优先级比加法运算更高,因此我们需要先计算乘法,再计算加法,而在Kotlin中是一样的,乘法和除法运算符的优先级是高于加法运算符的,所以说上面算出来的结果是7,同样的,我们数学中使用括号来提升某些运算的优先级,在Kotlin中同样可以,比如:

println((1 + 1) * 3)   //使用小括号来强制提升优先级

有些时候,我们可能想要让某个变量的值增加一定数值,比如下面这样:

var a = 10
a = a + 9   //让a等于a+9的结果

对于这种让变量本身加减乘除某个值的情况,可以使用赋值运算符简化:

a += 9   //等价于 a = a + 9
a /= 9   //等价于 a = a / 9
a %= 2   //等价于 a = a % 2

如果我们只是希望某个变量自增或自减1,那么我们可以像这样去写:

fun main() {
    var a = 10
    a++    //使用两个++表示自增1
    println(a)     //打印得到11
  	a--    //使用两个--表示自减1
}

不过,这个双++符号,可以放在变量的前后,都能实现自增操作:

var a = 10
++a   //最终效果等价于a++

但是他们有一个本质区别,就是++在前面,a是先自增再得到结果,而++在后面,是a先得到结果,再进行自增,比如:

fun main() {
    var a = 10
    println(a++)   //这里++在后面,打印a的值依然是10,但是结束之后a的值就变成11了
    println(++a)   //这里++在前面,打印a的值是这里先自增之后的结果,就是12了
}

位运算

Kotlin提供了一组整数的位运算操作,可以直接在二进制层面上与数字表示的位进行操作,不过只适用于 IntLong类型的数据:

  • shl(bits)– 有符号左移
  • shr(bits)– 有符号右移
  • ushr(bits)– 无符号右移
  • and(bits)– 按位与
  • or(bits)– 按位或
  • xor(bits)– 按位异或
  • inv()– 取反
按位与

这里我们从按位与开始讲解,比如下面的两个数:

fun main() {
    val a = 9
    val b = 3
    val c = a and b //进行按位与运算
    println(c)
}

按位与实际上就是让这两个数每一位都进行比较,如果这一位两个数都是1,那么结果就是1,否则就是0:

  • a = 9 = 1001
  • b = 3 = 0011
  • c = 1 = 0001(因为只有最后一位,两个数都是1,所以说结果最后一位是1,其他都是0)
按位或

同样的,按位或,其实就是只要任意一个为1(不能同时为0)那么结果就是1:

fun main() {
    val a = 9
    val b = 3
    val c = a or b
    println(c)
}
  • a = 9 = 1001
  • b = 3 = 0011
  • c =11= 1011(只要上下有一个是1或者都是1,那结果就是1)
按位异或

按位异或的意思就是只有两边不相同的情况下,结果才是1,也就是说一边是1一边是0的情况:

  • a = 9 = 1001
  • b = 3 = 0011
  • c =10= 1010(从左往右第二位、第四位要么两个都是0,要么两个都是1,所以说结果为0)
按位取反

按位取反操作跟前面的正负号一样,只操作一个数,最好理解,如果这一位上是1,变成0,如果是0,变成1:

  • 127 = 01111111
  • -128 = 10000000

所以说计算的结果就是-128了。

位移运算符

除了以上的四个运算符之外,还有位移运算符,比如:

fun main() {
    val c = 1 shl 2 //shl表示左移运算
    println(c)
}
  • 1 = 00000001
  • 4 = 00000100(左移两位之后,1跑到前面去了,尾部使用0填充,此时就是4)

我们发现,左移操作每进行一次,结果就会x2,所以说,除了直接使用 *进行乘2的运算之外,我们也可以使用左移操作来完成。

同样的,右移操作就是向右移动每一位咯:

fun main() {
    val c = 8 shr 2  //shr表示右移运算
    println(c)
}

跟上面一样,右移操作可以快速进行除以2的计算。对于负数来说,左移和右移操作不会改变其符号位上的数字,符号位不受位移操作影响:

fun main() {
    val c = -8 shr 2   //这里得到的依然是个负数
    println(c)
}

我们也可以使用考虑符号位的右移操作,一旦考虑符号位,那么符号会被移动:

fun main() {
    val c = -1 ushr 1 //无符号右移是ushr,移动会直接考虑符号位
    println(c)
}

比如:

  • -1 = 11111111 11111111 11111111 11111111
  • 右移: 01111111 11111111 11111111 11111111(无符号右移使用0填充高位)

此时得到的结果就是正数的最大值 2147483647 了,注意,不存在无符号左移操作。

最后我们再总结一下不同运算符的优先级,对应的优先级从上往下依次减弱:

  1. 一元运算符:例如 ++、--、+、-、!、~
  2. 乘法和除法运算符:*、/、%
  3. 加法和减法运算符:+、-
  4. 位移运算符:shl、shr、ushr
  5. 按位与运算符:and
  6. 按位或运算符:or
  7. 按位异或运算符:xor
  8. 逻辑运算符:&&、||
  9. 比较运算符:>、>=、<、<=、==、!=
  10. 区间运算符:..
  11. 赋值运算符:=、+=、-=、*=、/=、%=

布尔类型

布尔类型是Kotlin中的一个比较特殊的类型,它并不是存放数字的,而是状态,它有下面的两个状态:

  • true - 真
  • false - 假

布尔类型(boolean)只有 truefalse两种值,也就是要么为真,要么为假,布尔类型的变量通常用作流程控制判断语句(不同于C语言,C语言中一般使用0表示false,除0以外的所有数都表示true)

val a: Boolean = true

如果给一个其他的值,会无法编译通过:

hMkCfA6DVpWTPIi.png

布尔值除了可以直接赋值得到,也可以通过一些关系运算得到,常见的关系运算有大于、小于以及等于,所有的关系运算在下方:

  • 判断两个数是否相等:a == ba != b
  • 判断数之间大小:a < ba > ba <= ba >= b
  • 判断数是否在指定范围中:a..bx in a..bx !in a..b

比如我们想判断变量a和变量b的值是否相同:

fun main() {
    val a = 10
    val b = 8
    println(a == b)  //判断a是否等于b(注意等号要写两个,因为单等号为赋值运算)
    println(a >= b)   //判断a是否大于等于b
    println(a < b)   //判断a是否小于b
  	val c: Boolean = a != b   //判断a是否不等于b并将结果赋值给变量c
}

​ ​ 可以看到,通过逻辑运算得到的结果,都是true或false,也就是我们这里学习的Boolean类型值。在Kotlin中,我们为了快速判断某个数是否在一个区间内,可以直接使用 a..b 来表示一个数学上 [a, b]这样的闭区间,比如我们这里要判断变量 a的值是否在1~10之间:

fun main() {
    val a = 10
    println(a in 1..10)   //这里1..10表示1~10这个闭区间,使用in关键字来进行判断
  	println(a in 1..<10)   //这里1..<10表示1~10这个前闭后开区间,使用in关键字来进行判断
  	println(a !in 1..10)   //相反的,使用!in判断是否不在这个区间
}

对于Boolean类型的变量之间,也有一些逻辑运算符用于进行组合条件判断:

  • ||– 逻辑或运算
  • &&– 逻辑与运算
  • !– 取反运算

其中取反运算最好理解,它可以让true变成false,false变为true,比如:

fun main() {
    val a = 10
    val b = 20
    val c = a > b   //这里很明显c应该为false
    println(!c)   //这里进行了取反操作并打印,那么结果就是true了
}

对于逻辑与和逻辑或运算,我们可以像这样去使用:

fun main() {
    val a = 10
    val b = 0
    println(100 >= a && b >= 60)  //我们可以使用与运算符连接两个判断表达式,只有两边都为true结果才是true
    println(100 >= a || b >= 60)  //我们可以使用或运算符连接两个判断表达式,只要两边任意一个为true结果就是true
}

​ ​ 与运算符要求左右两边同时为真,得到的结果才是真,否则一律为假,而或运算就是要求两边只要有一边为真,结果就是真,除非两边同时为false,那么就没戏了。

​ ​ 不过需要注意的是,在与运算中,第一个判断表达式得到了 false之后,此时不会再继续运行第二个表达式,而是直接得到结果 false(逻辑运算符会出现短路的情况,只要第一个不是真,就算第二个是真也不可能了,所以说为了效率,后续就不用再判断了,在使用时一定要注意这一点)同样的,或运算下当发现第一个判断表达式为true时,也不会继续向后执行了,因为结果已经是顶真了。

字符类型

​ ​ 字符类型也是一个重要的基本数据类型,它可以表示计算机中的任意一个字符(包括中文、英文、标点等一切可以显示出来的字符)字符由 Char类型表示,字符值用单引号:'1'囊括:

val c: Char = 'A'
println(c)

注意,字符只能表示一单个字符,我们之前遇到的字符串跟字符不一样,关于字符串我们会在下节课进行介绍。

我们打印出来的也是单个字符:

lS12kDwfR9TrO4b.png

那么可能会有小伙伴好奇,字符类型在计算机底层是怎么进行存储的呢?实际上每个字符在计算机中都会对应一个字符码,首先我们需要介绍ASCII码:

Z7AiBPNO6ylML4z.png

比如我们的英文字母 A要展示出来,那就是一个字符的形式,而其对应的ASCII码值为65,我们可以使用 .code来获取某个字符对应的ASCII码,比如下面这样:

fun main() {
    val c: Char = 'A'
    println(c.code)   //这里就会打印字符对应的ASCII码
}

得到结果为:

a4ZRYXcK5E7d1MP.png

字符型占据2个字节的空间用于存放数据:

  • char 字符型(16个bit,也就是2字节,它不带符号)范围是0 ~ 65535

​ ​ 不过,这里的字符表里面不就128个字符吗,那 char干嘛要两个字节的空间来存放呢?我们发现表中的字符远远没有我们所需要的那么多,这里只包含了一些基础的字符,中文呢?那么多中文字符(差不多有6000多个),用ASCII编码表那128个肯定是没办法全部表示的,但是我们现在需要在电脑中使用中文,这时,我们就需要扩展字符集了。

Unicode是一个用于表示文本字符的标准字符集。它包含了世界上几乎所有的已知字符,包括不同国家和地区的字母、数字、标点符号、符号图形以及特殊的控制字符。

与Unicode不同,ASCII(American Standard Code for Information Interchange)是一个只包含128个字符的字符集。它最初是为了在计算机系统中传输基本英语字符而设计的。ASCII字符集包含了常见的拉丁字母、数字、标点符号以及一些特殊字符。

Unicode采用了一个更加广泛的字符编码方案,包括了不同的字符集编码,比如UTF-8和UTF-16等。UTF-8是一种可变长度的编码方案,它可以用来表示Unicode中的任意字符,且向后兼容ASCII字符集。而UTF-16则是一种固定长度的编码方案,它使用两个字节来表示一个Unicode字符。

与ASCII相比,Unicode的主要优势在于它能够表示各种不同的语言和字符,而不仅仅限于英语字符。这使得Unicode成为全球通用的字符编码标准,为不同国家和地区的语言提供了统一的编码方式。

所以,一个Char就能表示几乎所有国家语言的字符,这样就很方便了。

接着我们来介绍一下转译字符,对于一些我们平时很难直接通过键盘或是输入法打出来的字符,比如一些特殊符号:

ugem2scKxyX7wJL.png

这些符号我们没办法直接打出来,但是现在我们又想要表示它们,该怎么做呢?我们可以使用转义来将这些字符对应的Unicode编码转换为对应的字符,只需要在前面加上 \u即可,比如✓这个符号:

fun main() {
    val c = '\u2713'   //符号✓对应的Unicode编码为10003,这里需要转换为16进制表示,结果为0x2713
    println(c)
}

除了能像这样表示一个特殊字符,我们也可以使用一些其他的转义字符来表示各种东西:

  • \t – 选项卡
  • \b – 退格
  • \n – 换行(LF)
  • \r – 回车(CR)
  • \' – 单引号
  • \" – 双引号
  • \\ –反斜杠
  • \$ – 美元符号

这些转义字符都是为了防止在特殊情况下无法表示某些字符,而给我们的替代方案,后续各位小伙伴在使用时可以回来参考一下。

字符串类型

​ ​ 字符串类是一个比较特殊的类型,它用于保存字符串。我们知道,基本类型 Char可以保存一个2字节的Unicode字符,而字符串则是一系列字符的序列,它的类型名称为 String

字符串通常由双引号 ""囊括,它可以表示一整串字符:

val str: String = "Hello World"

注意,字符串中的字符一旦确定,无法进行修改,只能重新创建。

如果我们需要再字符串中换行,需要用到转义字符,字符串中同样支持使用转义字符:

fun main() {
    val text = "Hello\nWorld"
    println(text)
}

不过,字符串只能写一行,有时候有点不太够用,可能我们想要打印多行文本,我们除了用 \n转义字符来换行之外,也可以直接使用三个双引号 """来表示一个原始字符串,但是原始字符串无法使用转义字符:

fun main() {
    val text = """
    这是第一行
    这第二行
    别\n了,没用
    真牛逼啊,这功能隔壁Java15才有
    """
    println(text)
}

效果如下:

Y5fbh8FEOZcsMVz.png

​ ​ 可以看到确实是够原始的,把我代码里面的缩进都给打印出来了,这样肯定不是我们希望的样子,我们希望的仅仅是一个简单换行而已,那这里该怎么去处理呢?后面我们在讲解函数之后,会额外补充这里的内容。

有时候为了方便,我们可以将不同的字符串拼接使用:

fun main() {
    val str1 = "Hello"
    val str2 = "World"
    val str = str1 + str2
    println(str)   //使用 + 来拼接两个字符串,得到的结果就是两个字符串合在一起的结果
}

字符串除了和字符串拼接之外,也可以和其他类型进行拼接:

fun main() {
    val a = 10
    val text = "这是拼接的值" + a
    println(text)   //打印出来就是与其他类型的拼接结果
}

但是我们需要注意字符串拼接的顺序,只能由字符串拼接其他类型,如果是其他类型拼接字符串,可能会出现问题:

AZSxuKqRvMohp8I.png

但是现在我们就是希望其他类型的数据拼在最前面,这里应该怎么做呢?我们可以使用字符串模版来完成:

fun main() {
    val a = 10
    val text = "这是拼接的值$a"  //这里的$为模版表达式,可以直接将后面跟着的变量或表达式以字符串形式替换到这个位置
    println(text)
}

如果要添加到前面:

val text = "$a 这是拼接的值" //注意这里$a之后必须空格,否则会把后面的整个字符串认为这个变量的名字

出现这种情况除了用空格去解决之外,我们也可以添加一个花括号:

val text = "${a}这是拼接的值"  //添加花括号就可以消除歧义了
val text = "${a > 0}这是拼接的值"  //花括号中也可以写成表达式

由于美元符用于模版表达式了,所以说如果我们希望在字符串中仅仅表示$这个字符,那么我们需要用到转义:

val text = "\$这是美元符"   //普通字符串直接使用\$表示
//原始字符串要套个娃
val str = """
  ${'$'}这是美元符  
	"""
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区