Kotlin is a modern, statically typed, general-purpose programming language developed by JetBrains. It is designed to be fully interoperable with Java and primarily targets the Java Virtual Machine (JVM), but also compiles to JavaScript (Kotlin/JS) for web applications and native code (Kotlin/Native) via LLVM for platforms like iOS, macOS, Linux, and Windows.

basic data types

In total, Kotlin has the following basic types:

CategoryBasic typesExample code
IntegersByte, Short, Int, Longval year: Int = 2020
Unsigned integersUByte, UShort, UInt, ULongval score: UInt = 100u
Floating-point numbersFloat, Doubleval currentTemp: Float = 24.5f, val price: Double = 19.99
BooleansBooleanval isEnabled: Boolean = true
CharactersCharval separator: Char = ','
StringsStringval message: String = "Hello, world!"
Unsigned integers(无符号整数): An unsigned integer is a whole number variable in computer science that can only represent non-negative values (zero and positive numbers). Unlike signed integers, which can represent both positive and negative numbers, unsigned integers allocate all available bits to represent the magnitude of the number, allowing for a larger range of positive values for a given number of bits.

For more information on basic types and their properties, see Basic types.

With this knowledge, you can declare variables and initialize them later. Kotlin can manage this as long as variables are initialized before the first read.

To declare a variable without initializing it, specify its type with :. For example:

// Variable declared without initialization
val d: Int
// Variable initialized
d = 3
 
// Variable explicitly typed and initialized
val e: String = "hello"
 
// Variables can be read because they have been initialized
println(d) // 3
println(e) // hello

If you don’t initialize a variable before it is read, you see an error:

// Variable declared without initialization
val d: Int
 
// Triggers an error
println(d)
// Variable 'd' must be initialized

Explicitly declare the correct type for each variable:

fun main() {
    val a: Int = 1000 
    val b: String = "log message"
    val c: Double = 3.14
    val d: Long = 100_000_000_000_000
    val e: Boolean = false
    val f: Char = '\n'
}

can be simplified

fun main() {
    val a: Int = 1000 
    val b = "log message"
    val c = 3.14
    val d = 100_000_000_000_000
    val e = false
    val f = '\n'
}

数组

数组是一种保存固定数量相同类型或其子类型的值的数据结构。 Kotlin 中最常见的数组类型是对象类型数组,由 Array 类表示。
如果在对象类型数组中使用原生类型,那么会对性能产生影响,因为原生值都装箱成了对象。 为了避免装箱开销,请改用原生类型数组。

创建数组

To create arrays in Kotlin, you can use:

This example uses the arrayOf() function and passes item values to it:

fun main() {
//sampleStart
    // Creates an array with values [1, 2, 3]
    val simpleArray = arrayOf(1, 2, 3)
    println(simpleArray.joinToString())
    // 1, 2, 3
//sampleEnd
}

This example uses the arrayOfNulls()) function to create an array of a given size filled with null elements:

fun main() {
//sampleStart
    // Creates an array with values [null, null, null]
    val nullArray: Array<Int?> = arrayOfNulls(3)
    println(nullArray.joinToString())
    // null, null, null
//sampleEnd
}

You can specify the type of the empty array on the left-hand or right-hand side of the assignment due to Kotlin's type inference.

For example:

var exampleArray = emptyArray<String>()
// the two lines are both the same 
var exampleArray: Array<String> = emptyArray()

何时使用数组

当需要满足特殊的底层需求时,可以在 Kotlin 中使用数组。 例如,如果性能要求超出了常规应用程序的需要,或者需要构建自定义的数据结构。 如果没有这些限制,那么请改用集合。

与数组相比,集合具有以下优点:

  • 集合可以是只读的,这提供了更多的控制权而支持编写具有明确意图的健壮代码。
  • 易于对集合增删元素。相比之下,数组大小是固定的。 对数组增删元素的唯一方式是每次创建一个新数组,效率很低:
fun main() {
//sampleStart
    var riversArray = arrayOf("Nile", "Amazon", "Yangtze")
 
    // 使用 += 赋值操作创建了一个新的 riversArray,
    // 复制了原始元素并添加了“Mississippi”
    riversArray += "Mississippi"
    println(riversArray.joinToString())
    // Nile, Amazon, Yangtze, Mississippi
//sampleEnd
}
  • 可以使用相等操作符(==)来检验两个集合是否在结构上相等。但不能对数组使用这个操作符。 相反,必须使用一个特殊函数,关于这点可以参阅比较数组了解更多信息。

原生类型数组

If you use the Array class with primitive values, these values are boxed into objects. As an alternative, you can use primitive-type arrays, which allow you to store primitives in an array without the side effect of boxing overhead:

Primitive-type arrayEquivalent in Java
BooleanArrayboolean[]
ByteArraybyte[]
CharArraychar[]
DoubleArraydouble[]
FloatArrayfloat[]
IntArrayint[]
LongArraylong[]
ShortArrayshort[]
These classes have no inheritance relation to the Array class, but they have the same set of functions and properties.

This example creates an instance of the IntArray class:

fun main() {
//sampleStart
    // Creates an array of Int of size 5 with the values initialized to zero
    val exampleArray = IntArray(5)
    println(exampleArray.joinToString())
    // 0, 0, 0, 0, 0
//sampleEnd
}

I/O

password.txt放大 resource目录

fun main() {  
    println(readFile("password.txt"))  // readFile
}  
  
  
fun readFile(fileName: String): String {  
	// 通过当前类的class获取stream
	// 不使用类加载器`ClassLoader`
   val stream = object {}.javaClass.getResourceAsStream("/$fileName")  
        ?: throw IllegalArgumentException("Resource not found: $fileName")  
    return stream.bufferedReader().use { it.readText() }  
}
companion object{
		val PATH: Path = FabricLoader.getInstance().gameDir.resolve("genshin_impact_config")
}
 
private val configFile: File
		get() = PATH.resolve("config.json").toFile()
 
fun saveConfig(){
		if(!PATH.toFile().exists()){
			PATH.createDirectories()
		}
		try {
				val modules = Genshin.moduleManager.getModules()
				val map = HashMap<String, Boolean>()
				modules.forEach { module ->
						// 以模块名为 key,保存是否启用
						map[module.javaClass.simpleName] = module.isEnabled() // 遍历每个module,加入 map集合
				}
 
				FileWriter(configFile).use { writer ->
						gson.toJson(map, writer)
				}
				Genshin.LOGGER.info("Saved config to ${configFile.absolutePath}")
		} catch (e: IOException) {
				Genshin.LOGGER.error("Failed to save config", e)
		}
}