二、变量与基本类型

news2024/10/6 8:00:37

变量与基本类型

  • 变量
    • 定义
    • 声明和使用
  • 基本类型
    • 数字类型
      • 介绍
      • 运算
        • 算术运算符
        • 位运算符
        • 赋值运算符
        • 运算符优先级
    • 布尔类型
    • 字符类型
    • 字符串类型

变量

定义

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

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

声明和使用

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

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

这里的数据类型我们会在下节课开始逐步讲解,比如整数就是Int类型,不同类型的变量可以存储不同的类型的值。后面的变量名称顾名思义,就像x一样,这个名称我们可以随便起一个,但是注意要满足以下要求:

  • 可以由大小写字母、数字、下划线(_)组成,但是不能以数字开头。
  • 如果变量名加上反引号,则可以以数字开头,字符组成也可以包含空格、$等一些特殊字符,但<>.[];等一些字符依旧不行。
  • 变量不能重复定义,大小写敏感,比如A和a就是两个不同的变量。
  • 不能有空格、@、#、+、-、/ 等符号。
  • 应该使用有意义的名称,达到见名知意的目的(一般我们采用英文单词),最好以小写字母开头。
  • 不可以是 true 和 false。
  • 不能与Kotlin语言的关键字或是基本数据类型重名

当然各位小伙伴没必要刻意去进行记忆有哪些关键字,我们会在学习的过程中逐步认识到这些关键字。新手要辨别一个单词是否为关键字,只需要通过IDEA的高亮颜色进行区分即可,比如:
在这里插入图片描述

深色模式下,关键字会高亮为橙色,浅色模式下会高亮为深蓝色,普通的代码都是正常的灰白色。

比如现在我们想要定义一个整数(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 = 10
    println(a)
}

在这里插入图片描述

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

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关键字:

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

编译时得到报错:
在这里插入图片描述

常量的值只有第一次赋值可以修改,其他任何情况下都不行:

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

基本类型

数字类型

介绍

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

类型大小(位)最小值最大值
Byte8-128127
Short16-3276832767
Int32-2,147,483,648 (-2^31)2,147,483,647(2^31-1)
Long64-9,223,372,036,854,775,808 (-2^63)9,223,372,036,854,775,807(2^63 - 1)

为什么不同的数据类型有着值范围呢?这是因为我们的计算机底层是采用0和1表示数据的,并且数据的表示位数有限,我们以二进制来计算,就像下面这样:

1 + 1 = 10

可能很多小伙伴会好奇,为什么1 + 1得到的结果是数字十?这是因为二进制中只有0和1,因此只要满二就进一,所以就变成这样的结果了,如果各位是初次学习,可能会不太好理解。

这里以上面的8位大小的Byte类型为例,在计算机底层存储数据时,只有8个bit位(一个bit位就可以表示一个0或1)来存储它,那么它能表示的最大值和最小值就是:

00000000 ~ 11111111 转换为十进制就是 0 ~ 255

不过为了能够表示负数,计算机一般使用补码进行表示,所以,上面的最小值和最大值就变成了-128 ~ 127了。

默认情况下,我们使用的常量数字都是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进制的数字,接下来是2进制:

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位标准中的双精度数据,对于单双精度,本质上就是能够表示的小数位精度,双精度比单精度的小数精度更高。

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

类型大小(位)符号与尾数位数阶码位数小数位数
Float322486-7
Double64531115-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类型变量:
在这里插入图片描述

运算

算术运算符

Kotlin支持数学上标准的算术运算集,例如:+-*/% 并且这些运算符都是通过运算符重载实现的具体功能,我们会在后续的章节中讲解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. *=:乘法赋值运算符
  5. /=:除法赋值运算符
  6. %=:取余赋值运算符
运算符优先级

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

  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

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

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

  • 判断两个数/对象的值是否相等:a == ba != b
  • 判断两个数/对象的引用是否相等:a === b 和 a !== b
  • 判断数之间大小:a < ba > ba <= ba >= b
  • 判断数是否在指定范围中:a..bx in a..b(相当于x>=a && x<=b),x !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关键字来进行判断
  	// a in 1 until 10 == a in 1..<10
  	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)

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

我们打印出来的也是单个字符:
在这里插入图片描述

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

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

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

得到结果为:
在这里插入图片描述

字符型占据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就能表示几乎所有国家语言的字符,这样就很方便了。

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

这些符号我们没办法直接打出来,但是现在我们又想要表示它们,该怎么做呢?我们可以使用转义来将这些字符对应的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)
}

效果如下:
在这里插入图片描述

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

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

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

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

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

但是我们需要注意字符串拼接的顺序,只能由字符串拼接其他类型,如果是其他类型拼接字符串,可能会出现问题:
在这里插入图片描述

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

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 = """
  ${'$'}这是美元符    
	"""

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2191459.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java_Se 泛型

泛型基本概念&#xff1a; 泛型是JDK5.0以后增加的新特性。泛型的本质就是“数据类型的参数化”&#xff0c;处理的数据类型不是固定的&#xff0c;而是可以作为参数传入。我们可以把“泛型”理解为数据类型的一个占位符(类似&#xff1a;形式参数)&#xff0c;即告诉编译器&am…

如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程

Linux系统Docker搭建Poste.io电子邮件服务器&#xff0c;搭建属于自己的域名邮箱服务器&#xff0c;可以无限收发电子邮件&#xff08;Email&#xff09;&#xff01; 视频教程&#xff1a;https://www.bilibili.com/video/BV11p1mYaEpM/ 前言 什么是域名邮箱&#xff1f; …

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵 3.4 Softmax 回归3.4.1 分类问题3.4.2 网络架构 3.4.3 全连接层的参数开销3.4.4 softmax 运算3.4.5 小批量样本的向量化3.4.6 损失函数对数似然softmax 的导数 3.4.7 信息论基础熵信息量重新审…

MySQL 和 Elasticsearch 的应用场景

MySQL 和 Elasticsearch 的应用场景 一、MySQL 关系型数据库管理系统&#xff0c;用于存储和管理结构化数据。 存储数据场景&#xff1a; 企业的财务系统、人力资源系统等&#xff0c;需要存储和管理具有明确关系的数据&#xff0c;如员工信息表、工资表等&#xff0c;这些表…

一阶差分模板的频率响应

一阶差分模板不同于二阶差分模板&#xff0c;它是一个奇对称的模板&#xff0c;傅里叶变换是纯虚数&#xff0c;无法用图形直接显示傅里叶变换&#xff0c;只能显示幅值谱。 冈萨雷斯的这个图我一直很好奇是怎么显示的&#xff0c;也没有坐标轴标出变量表示。 如今终于想明白…

基于Es的分词查询通过高亮效果实现前端高亮显示!!!!

引言&#xff1a; 经常我们在浏览器界面搜索关键词的时候&#xff0c;浏览器返回给我们的页面都是高亮显示关键词的效果&#xff0c; 如下&#xff1a; 我们要简单实现这个效果很简单&#xff0c;可以通过多种办法&#xff0c;这里通过Es 的高亮效果实现给我们关键字字段加自…

FRP搭建内网穿透:云服务端 + 家用Linux/Windows主机【2024】

介绍 FRP是一个可以自己搭建内网穿透服务的开源项目&#xff0c;开源地址直达&#xff1a; FRP-GitHub 实际上frp由两个程序组成 ①frps:在服务端运行的程序 ②frpc:在客户端运行的程序 运作方式示意图如下 服务端 因为服务上使用了1Panel面板&#xff0c;直接在应用商店安…

每日一题|134. 加油站|循环数组单次遍历

本题题目比较绕&#xff0c;理解了之后发现就是给一个一维数组表示余量&#xff0c;找出能够首尾相连且后构成每个位置处的累积和都是正数的索引。 首先&#xff0c;根据cost和gas相减&#xff0c;确定每个位置出发去下一个位置所剩余的gas。 这里可以直接统计全部的余量和&…

【德国EnMAP高光谱卫星】

德国EnMAP&#xff08;Environmental Mapping and Analysis Program&#xff09;高光谱卫星是德国在地球观测领域的一项重要成就&#xff0c;以下是对该卫星的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2022年4月1日研发机构&#xff1a;由德国航空航天中心&a…

【多模态项目实战】-模态表示:基于对应表示的跨模态检索(图文互搜)

【多模态项目实战】-模态表示&#xff1a;基于对应表示的跨模态检索 文章目录 【多模态项目实战】-模态表示&#xff1a;基于对应表示的跨模态检索1.任务介绍2.跨模态检索技术简介3.模型训练流程3.1读取数据1)下载数据集&#x1f680;2)整理数据集3)定义数据集类4)批量读取数据…

zutilo不支持zotero7,zotero7实现复制条目链接方法。

更新zotero7后原来的zutilo插件失效了&#xff0c;为其中复制条目链接这个功能修改了一个脚本&#xff0c;仅粘贴链接&#xff0c;无标题。 {"translatorID": "2de2b1a5-5725-494c-9224-5781cdf9b7ef","label": "Markdown ZotSelect"…

读数据湖仓08数据架构的演化

1. 数据目录 1.1. 需要将分析基础设施放置在数据目录(Data Catalogue)的结构中 1.1.1. 元数据 1.1.2. 数据模型 1.1.3. 本体 1.1.4. 分类标准 1.2. 数据目录类似于图书馆的图书检索目录 1.2.1. 先通过图书馆的图书检索目录进行查找&#xff0c;以便快速找到所需的图书 1…

《深度学习》OpenCV 摄像头OCR 过程及案例解析

目录 一、摄像头OCR 1、含义 2、一般操作步骤 1&#xff09;安装OpenCV库 2&#xff09;设置摄像头 3&#xff09;图像采集 4&#xff09;图像预处理 5&#xff09;文本识别 6&#xff09;文本处理 7&#xff09;结果显示 二、案例实现 1、定义展示图像函数 2、定…

CANoe_TestModule截图功能TestReportAddWindowCapture

前言 TestReportAddWindowCapture方法作为CAPL脚本中的一个重要功能&#xff0c;其能够将指定窗口的屏幕截图添加到测试报告中&#xff0c;对于记录和验证界面状态具有重要意义。本文将全面解析TestReportAddWindowCapture方法的使用方法、参数解释、示例应用以及注意事项&…

从介质失效看互联网时代的信息过载

来读一篇文章&#xff1a;90年代的硬盘已大规模变砖&#xff0c;没啥好担心的&#xff0c;好事。 结合我两年前的粗浅认知 互联网时代无信息&#xff0c;按照 “动” 的观念看&#xff0c;当信息越来越多&#xff0c;信息密度越来越大时&#xff0c;信息的寿命就会越来越短&am…

智谱AI开源CogView3及升级版,文生图技术新突破!

Ai 智能办公利器 - Ai-321.com 智谱AI近日震撼宣布&#xff0c;向公众开放其最新研发的CogView3及进阶版CogView-3Plus-3B&#xff0c;这两款模型无疑为文本转图像技术领域带来了革命性的突破。 人工智能 - Ai工具集 - 全球热门人工智能软件ai工具集合网站 CogView3作为首款运…

PMP--三模--解题--161-170

文章目录 10.沟通管理--沟通管理计划--沟通管理计划是项目管理计划的组成部分&#xff0c;描述将如何规划、结构化、执行与监督项目沟通&#xff0c;以提高沟通的有效性。该计划包括如下信息&#xff1a;干系人的沟通需求。--凡信息&#xff0c;找沟通。161、 [单选] 一家公司的…

【X线源】微焦点X射线源的基本原理

【X线源】微焦点X射线源的基本原理 1.背景2.原理 1.背景 1895年11月8日&#xff0c;德国物理学家威廉伦琴在研究阴极射线时偶然发现了X射线。当时&#xff0c;他注意到阴极射线管附近的荧光屏发出了光&#xff0c;即使它被纸板遮挡住。经过进一步实验&#xff0c;他意识到这种…

开源模型应用落地-模型微调-模型研制-模型训练(二)

一、前言 模型训练是深度学习领域中的关键环节。随着技术的发展,预训练模型的出现极大地改变了模型构建的格局。这些预训练模型在大规模数据集上进行了初步的学习,蕴含了丰富的通用知识。然而,不同的实际应用场景有着各自独特的需求。例如在医疗影像诊断领域,预训练模型可能…

Linux和指令初识

前言 Linux是我们在服务器中常用的操作系统&#xff0c;我们有必要对这个操作系统有足够的认识&#xff0c;并且能够使相关的指令操作。今天我们就来简单的认识一下这个操作的前世今生&#xff0c;并且介绍一些基础的指令操作 Linux的前世今生 要说Linux&#xff0c;还得从U…