In the previous lesson, we set up our Kotlin learning environment and completed our first program. This lesson will delve into the core of Kotlin's basic syntax—variables, data types, and operators. These form the foundation of any programming language, and mastering them will enable you to write functional code, laying the groundwork for learning concepts like functions and classes in subsequent lessons.
I. Variables and Constants: "Data Containers" in Programs
Variables and constants are basic units for storing data. Kotlin makes a strict distinction between "mutability" and "immutability," which is an important difference from other languages like Python.
1. var (Mutable Variables) and val (Immutable Constants)
In Kotlin, variables are declared using var and val, with the key difference being whether they can be reassigned:
- var (short for variable): Declares a mutable variable that can be reassigned after initialization;
- val (short for value): Declares an immutable constant that cannot be reassigned after initialization (similar to final in Java).
// Mutable variable: can be reassigned
var age = 20
age = 21 // Valid, var allows modification
// Immutable constant: cannot be modified after initialization
val name = "Kotlin"
// name = "Java" // Compilation error! val does not allow reassignment
Best Practice: Prefer val and use var only when modification is truly necessary. This reduces "unexpected changes" in code, making programs more stable and maintainable (especially in multi-threaded scenarios).
2. Two Ways to Declare Variables: Explicit Typing vs. Type Inference
Kotlin is a statically typed language but supports "type inference," eliminating the need to explicitly specify variable types every time:
- Explicit typing: Format is var/val variableName: Type = value, clearly telling the compiler the variable's type;
- Type inference: Format is var/val variableName = value, where the compiler automatically infers the variable type from the assigned value.
// Explicit type specification
var score: Int = 95
val pi: Double = 3.14159
// Type inference (recommended)
var height = 175 // Compiler automatically infers Int type
val isStudent = true // Automatically infers Boolean type
Note: Type inference only works when a value is assigned during declaration. If declaring without an initial value (delayed initialization), you must explicitly specify the type:
var address: String // Delayed initialization, type must be explicitly specified
address = "Chaoyang District, Beijing" // Assignment later
3. Variable Scope: The "Effective Range" of Variables
A variable's scope refers to the range of code where it can be accessed. In Kotlin, there are mainly local variables and global variables:
(1) Local Variables
Variables defined inside functions or code blocks (like if or for blocks) that are only valid within their containing block:
fun printMessage() {
// Local variable inside function, only accessible in printMessage()
val message = "Hello, Local Variable"
println(message)
}
fun main() {
printMessage()
// println(message) // Compilation error! message is a local variable of printMessage()
}
(2) Global Variables
Variables defined at the top level of a file (not belonging to any function or class) that can be accessed throughout the file or class:
// Global variable at file level, accessible throughout the file
val globalVersion = "1.0.0"
fun checkVersion() {
println("Current version: $globalVersion") // Can directly access global variable
}
fun main() {
checkVersion() // Output: Current version: 1.0.0
}
Note: Global variables occupy memory continuously and should be used sparingly. Prefer local variables and follow the "minimum scope principle."
II. Basic Data Types: Kotlin's "Data Building Blocks"
Kotlin provides a rich set of basic data types for storing different kinds of data. Unlike Java, Kotlin's basic data types are not "primitive types" (like int) but "object types," while still maintaining efficient performance (optimized to primitive types during compilation).
1. Numeric Types: "Toolkit" for Storing Numbers
Kotlin offers 6 numeric types, ordered by precision and range from smallest to largest:
Type | Bits | Range | Example Usage |
---|---|---|---|
Byte | 8 | -128 ~ 127 | Storing small integers (saves space) |
Short | 16 | -32768 ~ 32767 | Medium-range integers |
Int | 32 | -2^31 ~ 2^31-1(约 -21 亿~21 亿) | Regular integers (default preference) |
Long | 64 | -2^63 ~ 2^63-1(约 -900 亿亿~900 亿亿) | Large integers |
Float | 32 | Single-precision floating point (~±3.4e38, 7 significant digits) | Decimals with low precision requirements |
Double | 64 | Double-precision floating point (~±1.8e308, 15 significant digits) | High-precision decimals (default preference) |
Usage Notes:
- When declaring Long types, append L suffix: val bigNum: Long = 10000000000L;
- When declaring Float types, append F suffix: val pi: Float = 3.14F;
- Integers default to Int type, decimals default to Double type.
val b: Byte = 127
val s: Short = 32000
val i = 1000 // Defaults to Int
val l = 10000000000L // Long type must have L suffix
val f = 3.14F // Float type must have F suffix
val d = 3.14159 // Defaults to Double
2. Character Type Char: "Container" for Single Characters
Char is used to store single characters, enclosed in single quotes '. There are specific rules to note regarding its interaction with numbers:
Kotlin allows Char types to be added to numbers when the Char is on the left side (the compiler automatically converts Char to its corresponding ASCII code for calculation), but does not allow numbers to be added to Char when the number is on the left side. This is a special rule in Kotlin syntax.
val c1: Char = 'A' // English character
val c2: Char = '中' // Chinese character (supports Unicode)
val c3: Char = '\u0041' // Unicode representation (corresponds to 'A')
// Special syntax rule: Char can be added to numbers when on the left
val y1 = 'A' + 1 // Valid, result is 'B' (ASCII code for 'A' is 65, +1 = 66, which is 'B')
// Numbers cannot be added to Char when on the left
// val y2 = 1 + 'A' // Compilation error! Kotlin does not allow numbers on left to add with Char directly
To convert a Char to its corresponding ASCII code, explicitly call the toInt() method, which allows correct calculation regardless of order:
val charCode = 'A'.toInt() // Convert to ASCII code 65
val sum = 1 + charCode // Valid, result is 66
println(sum.toChar()) // Output: 'B'
3. Boolean Type: "Switch" for Logical Judgments
Boolean represents logical values with only two possible values: true (true) and false (false), mainly used for conditional judgments (like if statements).
val isReady = true
val hasError = false
// Example of logical judgment
if (isReady) {
println("Ready")
} else {
println("Not ready")
}
III. String Type Detailed Explanation: "Powerful Tool" for Text Processing
Strings (String) are used to store text and are one of the most commonly used data types in programming. Kotlin offers flexible support for strings with various convenient operations.
1. String Creation: Single-line and Multi-line
Kotlin supports two ways to create strings:
- Single-line strings: Enclosed in double quotes "", content is within one line;
- Multi-line strings: Enclosed in triple quotes """, can contain line breaks directly and preserve formatting (no need for \n escape characters).
// Single-line string
val singleLine = "This is a single-line string"
// Multi-line string (preserves line breaks and indentation)
val multiLine = """
First line
Second line
Third line
""".trimIndent() // trimIndent() removes extra leading indentation from each line
println(multiLine)
// Output:
// First line
// Second line
// Third line
Note: Multi-line strings preserve leading indentation by default. The trimIndent() method automatically removes this extra indentation for cleaner output.
2. String Concatenation: Two Ways to Connect Text
There are two common methods for concatenating strings:
- + operator: Directly use + to connect strings and other data types;
- String templates: Use $ to reference variables or expressions, which is more concise and efficient.
val name = "Kotlin"
val version = 1.9
// + operator concatenation (more cumbersome)
val info1 = "Programming language: " + name + ", Version: " + version
println(info1) // Output: Programming language: Kotlin, Version: 1.9
// String template (recommended)
val info2 = "Programming language: $name, Version: $version"
println(info2) // Output: Same as above
// Using expressions in templates (needs ${})
val a = 10
val b = 20
val sumStr = "Sum of two numbers: ${a + b}" // Result of expression a + b will be inserted
println(sumStr) // Output: Sum of two numbers: 30
Advantage: String templates are more efficient than + concatenation (avoiding creation of excessive temporary strings) and make code more readable.
3. Common String Methods: "Toolkit" for Text Processing
Kotlin's String class provides numerous methods. Here are the most commonly used ones:
Method Name | Description | Example |
---|---|---|
length |
Gets string length (number of characters) | "hello".length → 5 |
substring(start, end) |
Extracts substring (from start to end-1) | "Kotlin".substring(1, 4) → "otl" |
equals(other) |
Checks if content equals (structural equality) | "a".equals("A") → false |
compareTo(other) |
Compares strings (lexicographical order) | "apple".compareTo("banana") → negative |
startsWith(prefix) |
Checks if starts with specified prefix | "Kotlin".startsWith("Ko") → true |
endsWith(suffix) |
Checks if ends with specified suffix | "Kotlin".endsWith("lin") → true |
trim() |
Removes leading and trailing whitespace | " hello ".trim() → "hello" |
split(delimiter) |
Splits string into list by delimiter | "a,b,c".split(",") → ["a", "b", "c"] |
val str = " Kotlin Programming "
println(str.length) // Output: 20 (including leading and trailing spaces)
println(str.trim()) // Output: "Kotlin Programming" (spaces removed)
println(str.startsWith("Ko")) // Output: false (original string has leading space)
println(str.trim().startsWith("Ko")) // Output: true (after trimming)
println(str.substring(2, 8)) // Output: "Kotlin" (extracts characters from index 2 to 7)
IV. Operators and Expressions: "Rules" for Data Operations
Operators perform operations on data, and when combined with variables and constants, form expressions (code fragments with return values). Most of Kotlin's operators are similar to Java's, with some subtle differences.
1. Arithmetic Operators: Handling Numeric Calculations
Operator | Function | Example |
---|---|---|
+ |
Addition | 5 + 3 → 8 |
- |
Subtraction | 5 - 3 → 2 |
* |
Multiplication | 5 * 3 → 15 |
/ |
Division |
5 / 2 → 2 (integer division) |
% |
Modulus (remainder) | 5 % 2 → 1 |
++ |
Increment | var a=1; a++ → 2 |
-- |
Decrement | var b=3; b-- → 2 |
Notes:
- Integer division (/) automatically discards the decimal part (e.g., 5 / 2 = 2 rather than 2.5);
- Difference between prefix and postfix increment/decrement (++/--):
- a++: Uses a's value first, then increments;
- ++a: Increments first, then uses a's value.
val num1 = 10
val num2 = 3
println(num1 + num2) // 13
println(num1 - num2) // 7
println(num1 * num2) // 30
println(num1 / num2) // 3 (integer division, decimal discarded)
println(num1.toDouble() / num2) // 3.333... (division after converting to Double)
println(num1 % num2) // 1 (10 divided by 3 leaves remainder 1)
var count = 5
println(count++) // Outputs 5 (uses then increments)
println(count) // Outputs 6
var score = 80
println(++score) // Outputs 81 (increments then uses)
println(score) // Outputs 81
2. Assignment Operators: Assigning Values to Variables
The basic assignment operator is =, with additional compound assignment operators (combining arithmetic operations and assignment):
Operator | Equivalent Expression | Example |
---|---|---|
= |
Direct assignment | a = 5 |
+= |
a = a + b |
a += 3 → a = a + 3 |
-= |
a = a - b |
a -= 2 → a = a - 2 |
*= |
a = a * b |
a *= 4 → a = a * 4 |
/= |
a = a / b |
a /= 2 → a = a / 2 |
%= |
a = a % b |
a %= 3 → a = a % 3 |
var x = 10
x += 5 // Equivalent to x = x + 5 → x = 15
x *= 2 // Equivalent to x = x * 2 → x = 30
x -= 8 // Equivalent to x = x - 8 → x = 22
println(x) // Output: 22
3. Comparison Operators: Judging Data Relationships
Comparison operators determine relationships between two data items, returning Boolean values (true or false).
Operator | Description | Example |
---|---|---|
== |
Checks content equality (structural) | "abc" == "abc" → true |
!= |
Checks content inequality | 5 != 3 → true |
> |
Greater than | 10 > 5 → true |
< |
Less than | 10 < 5 → false |
>= |
Greater than or equal to | 5 >= 5 → true |
<= |
Less than or equal to | 3 <= 2 → false |
=== |
Checks reference equality | (See explanation below) |
Key Difference: == vs ===
- ==: Checks "structural equality" (whether content is the same), equivalent to Java's equals() method;
- ===: Checks "reference equality" (whether they point to the same object in memory), equivalent to Java's == operator.
val str1 = "Hello"
val str2 = "Hello"
val str3 = String("Hello".toCharArray()) // Creates new string object with same content
println(str1 == str2) // true (same content)
println(str1 == str3) // true (same content)
println(str1 === str2) // true (Kotlin string constant pool optimization, same reference)
println(str1 === str3) // false (str3 is new object, different reference)
4. Logical Operators: Combining Conditional Judgments
Logical operators connect multiple boolean expressions for complex logical judgments:
Operator | Description | Example |
---|---|---|
&& |
Logical AND (short-circuit) | true && false → false |
|| | Logical OR (short-circuit) |
true ||false → true
|
! |
Logical NOT | !true → false |
Short-circuit Characteristics:
- &&: If the left expression is false, the right expression will not execute (since overall result is already false);
- ||: If the left expression is true, the right expression will not execute (since overall result is already true).
val hasMoney = true
val hasTime = false
// Logical AND: returns true only if both conditions are true
val canBuy = hasMoney && hasTime
println(canBuy) // false (hasTime is false)
// Logical OR: returns true if at least one condition is true
val canRelax = hasMoney || hasTime
println(canRelax) // true (hasMoney is true)
// Logical NOT: negation
val isPoor = !hasMoney
println(isPoor) // false
// Short-circuit example
var count = 0
val result = false && (count++ > 0) // Left is false, right doesn't execute
println(count) // 0 (count not incremented)
V. Type Conversion: "Bridge" Between Different Data Types
Kotlin does not support "implicit type conversion" (like Java's automatic conversion from int to long). You must explicitly call conversion methods. Each basic type provides methods to convert to other types (e.g., toInt(), toDouble()).
val numInt: Int = 100
// val numLong: Long = numInt // Compilation error! Kotlin doesn't allow implicit conversion
val numLong: Long = numInt.toLong() // Correct: explicitly convert to Long
val numFloat: Float = numInt.toFloat() // Convert to Float
val numStr: String = numInt.toString() // Convert to string
// String to number (ensure string contains valid number)
val str = "123"
val strToInt = str.toInt() // Convert to Int
val strToDouble = str.toDouble() // Convert to Double
Note: Converting a string to a number will throw a NumberFormatException if the content isn't a valid number (e.g., "abc"). We'll cover handling such exceptions in later lessons.
VI. Practical Exercise: "Mini Project" to Reinforce Basics
To help you consolidate what you've learned, let's write a simple "personal information card" program that integrates variables, data types, and operators:
fun main() {
// 1. Define personal information variables
val name = "Zhang San"
var age = 25
val height: Double = 1.75
val isStudent = true
// 2. Calculate age next year (using arithmetic operators)
val nextYearAge = age + 1
// 3. Combine personal information into string (using string templates)
val info = """
Personal Information Card
Name: $name
Current Age: $age
Age Next Year: $nextYearAge
Height: ${height}m
Is Student: ${if (isStudent) "Yes" else "No"} // Using expression in template
""".trimIndent()
// 4. Output result
println(info)
}
After running the program, the output will be:
Personal Information Card
Name: Zhang San
Current Age: 25
Age Next Year: 26
Height: 1.75m
Is Student: Yes
Try modifying variable values or adding more information (like weight or hobbies) to observe output changes and deepen your understanding of the concepts.
Top comments (1)
Nice posting, Interested in talking to you, could you share your email address?