Lập trình · Ngôn ngữ lập trình
Hướng dẫn học lập trình Swift cơ bản cho người mới
Trả lời nhanh
Swift là ngôn ngữ biên dịch nhanh và an toàn do Apple tạo ra cho ứng dụng iPhone, iPad, Mac, Apple Watch và Apple TV, đồng thời cũng chạy được trên Linux và Windows. Lưu print("Hello, world") vào hello.swift rồi chạy swift hello.swift. Các ý tưởng cốt lõi là hằng số let và biến var, suy luận kiểu, optional cho những giá trị có thể không có, struct và enum có ngữ nghĩa giá trị, protocol, và lỗi được xử lý bằng do/try/catch.
Swift là gì và dùng để làm gì
Apple giới thiệu Swift năm 2014 như một sự thay thế hiện đại cho Objective-C và mở mã nguồn năm 2015; dự án nằm tại swift.org. Đây là ngôn ngữ chính cho ứng dụng trên các nền tảng của Apple, thường đi cùng framework SwiftUI hoặc UIKit. Swift cũng được dùng cho mã phía máy chủ (ví dụ với framework Vapor) và công cụ dòng lệnh. Ngôn ngữ được thiết kế để ngăn các lỗi phổ biến: biến phải được khởi tạo, mảng kiểm tra chỉ số vượt giới hạn, và nil phải được xử lý một cách tường minh.
Cài Swift và chạy Hello, world
Trên Mac, cài Xcode từ App Store hoặc bộ công cụ dòng lệnh của Xcode. Trên Linux và Windows, tải toolchain từ swift.org. Kiểm tra bằng swift --version.
print("Hello, world")swift hello.swift
# Hello, world
swiftc hello.swift -o hello # compile to a binary
./helloVới dự án lớn hơn, chạy swift package init --type executable rồi swift run. Playground của Xcode là một cách dễ khác để thử nghiệm.
Hằng số, biến và các kiểu dữ liệu cơ bản
Dùng let cho hằng số và var cho biến. Nên ưu tiên let; trình biên dịch sẽ cảnh báo khi một var không bao giờ bị thay đổi. Kiểu được suy luận, và Swift không bao giờ tự chuyển đổi giữa các kiểu số.
| Kiểu | Ví dụ | Ghi chú |
|---|---|---|
Int | let n = 42 | 64 bit trên các nền tảng hiện đại |
Double | let x = 3.14 | Kiểu số thực mặc định |
Bool | let ok = true | true hoặc false |
String | let s = "hi \(name)" | Văn bản Unicode, kiểu giá trị |
Character | let c: Character = "é" | Một ký tự theo cảm nhận của người dùng |
[Int], [String: Int] | [1, 2], ["a": 1] | Mảng và dictionary |
let name = "Ada"
var count = 7
count += 1
let avg = Double(count) / 2 // explicit conversion
print("\(name) has \(count) items, avg \(avg)") // Ada has 8 items, avg 4.0
print(7 / 2, 7 % 2) // 3 1\(expression) bên trong một chuỗi ký tự sẽ chèn một giá trị vào (nội suy chuỗi).
Điều khiển luồng
let score = 72
if score >= 90 {
print("A")
} else if score >= 70 {
print("B") // B
} else {
print("C")
}
for i in 0..<3 {
print(i, terminator: " ") // 0 1 2
}
print()
var n = 10
while n > 1 { n /= 2 }
print(n) // 1
let day = "SAT"
switch day {
case "SAT", "SUN":
print("weekend") // weekend
default:
print("weekday")
}switch phải bao quát mọi trường hợp, mặc định không chạy tràn xuống nhánh sau, và có thể khớp theo khoảng (case 90...100:), tuple và các case của enum.
Hàm và closure
Tham số có nhãn đối số mà bên gọi phải viết, khiến lời gọi đọc như một câu. Dùng _ để bỏ nhãn. Closure là hàm không tên được viết trong cặp ngoặc nhọn.
func greet(_ name: String, with greeting: String = "Hello") -> String {
return "\(greeting), \(name)!"
}
print(greet("Lin")) // Hello, Lin!
print(greet("Lin", with: "Hi")) // Hi, Lin!
let nums = [3, 1, 2, 5]
let squares = nums.map { $0 * $0 }
let evens = nums.filter { $0 % 2 == 0 }
let sorted = nums.sorted(by: >)
print(squares, evens, sorted) // [9, 1, 4, 25] [2] [5, 3, 2, 1]$0 chỉ đối số đầu tiên của closure. Khi closure là đối số cuối cùng, có thể viết nó sau cặp ngoặc tròn (cú pháp trailing closure).
Mảng, dictionary và set
var fruits = ["apple", "pear"]
fruits.append("fig")
print(fruits.count, fruits[0], fruits.contains("fig")) // 3 apple true
var ages: [String: Int] = ["ann": 31, "bob": 25]
ages["cy"] = 40
for (person, age) in ages.sorted(by: { $0.key < $1.key }) {
print(person, age) // ann 31, bob 25, cy 40
}
print(ages["zed", default: 0]) // 0
let tags: Set = ["b", "a", "b"]
print(tags.count) // 2Collection là kiểu giá trị: gán một mảng cho biến khác sẽ tạo ra bản sao độc lập (sao chép lười, chỉ khi một trong hai bị thay đổi). Mảng khai báo bằng let hoàn toàn không thể sửa đổi.
Tính năng đặc trưng: optional
Giá trị có thể không tồn tại có kiểu optional, viết là String?. Bạn không thể dùng nó như một String cho đến khi mở gói (unwrap), nên trình biên dịch buộc bạn xử lý trường hợp nil.
let input = "42"
let number: Int? = Int(input) // nil if input is not a number
if let number { // unwrap: runs only when not nil
print("got \(number)") // got 42
}
func firstWord(_ text: String) -> String? {
text.split(separator: " ").first.map(String.init)
}
guard let word = firstWord("hello world") else {
fatalError("no words")
}
print(word) // hello
print(firstWord("")?.uppercased() ?? "none") // noneif let và guard let mở gói an toàn, ?. (optional chaining) chỉ gọi phương thức khi giá trị tồn tại, còn ?? cung cấp giá trị mặc định. Việc mở gói cưỡng bức value! sẽ làm chương trình sập khi giá trị là nil, nên hãy dùng thật hiếm. Dạng rút gọn if let number cần Swift 5.7 trở lên.
Struct, class, enum và protocol
Struct và enum là kiểu giá trị; class là kiểu tham chiếu có kế thừa. Mã Swift ưu tiên struct và protocol (interface) hơn là cây phân cấp lớp.
protocol Shape {
func area() -> Double
}
struct Rect: Shape {
var width: Double
var height: Double
func area() -> Double { width * height }
}
enum Circle: Shape {
case unit
case radius(Double)
func area() -> Double {
switch self {
case .unit: return Double.pi
case .radius(let r): return Double.pi * r * r
}
}
}
let shapes: [any Shape] = [Rect(width: 2, height: 3), Circle.radius(1)]
let total = shapes.reduce(0) { $0 + $1.area() }
print((total * 100).rounded() / 100) // 9.14Struct tự động có hàm khởi tạo theo từng thành viên (Rect(width:height:)). Các case của enum có thể mang giá trị liên kết, như .radius(Double).
Xử lý lỗi
Hàm có thể thất bại được đánh dấu throws. Bên gọi phải dùng try bên trong khối do/catch, hoặc dùng try? để biến lỗi thành nil.
enum AgeError: Error {
case notANumber(String)
case negative
}
func parseAge(_ text: String) throws -> Int {
guard let age = Int(text) else { throw AgeError.notANumber(text) }
guard age >= 0 else { throw AgeError.negative }
return age
}
do {
print(try parseAge("41")) // 41
print(try parseAge("abc"))
} catch AgeError.notANumber(let text) {
print("not a number: \(text)") // not a number: abc
} catch {
print("other error: \(error)")
}
let maybe = try? parseAge("-3") // nil
print(maybe as Any) // nilMột chương trình hoàn chỉnh nhỏ: tần suất từ
import Foundation
let args = CommandLine.arguments
guard args.count == 2 else {
print("usage: swift words.swift FILE")
exit(1)
}
do {
let text = try String(contentsOfFile: args[1], encoding: .utf8).lowercased()
let words = text.split { !$0.isLetter && $0 != "'" }
var counts: [Substring: Int] = [:]
for word in words {
counts[word, default: 0] += 1
}
for (word, n) in counts.sorted(by: { $0.value > $1.value }).prefix(5) {
print(String(n).padding(toLength: 6, withPad: " ", startingAt: 0) + word)
}
} catch {
print("cannot read \(args[1]): \(error.localizedDescription)")
exit(1)
}Chạy bằng swift words.swift notes.txt. Foundation cung cấp việc đọc tệp và các hàm hỗ trợ chuỗi; thư viện này có trên các nền tảng Apple và trong toolchain cho Linux và Windows.
Lỗi thường gặp của người mới
- Cố thay đổi hằng số
lethoặc thuộc tính của một struct khai báo bằnglet. Hãy dùngvarkhi giá trị cần thay đổi. - Mong struct được chia sẻ như một đối tượng. Thay đổi bản sao không làm đổi bản gốc; hãy dùng class nếu cần danh tính dùng chung.
- Truy cập
Stringbằng số nguyên, chẳng hạns[0]. Hãy dùngs.first,s.prefix(3)hoặc các giá trịString.Index. - Trộn
IntvàDoubletrong phép tính mà không chuyển đổi, đây là lỗi biên dịch. - Quên
trytrước lời gọi có thể ném lỗi, hoặc dùngtry!, vốn làm chương trình sập khi có lỗi.
Học tiếp ở đâu
Đọc "The Swift Programming Language" trên docs.swift.org, là hướng dẫn và tài liệu tham chiếu chính thức, cùng trung tâm tài liệu trên swift.org. Với ứng dụng, hãy làm theo các hướng dẫn SwiftUI của Apple trong Xcode. Sau đó học lập trình đồng thời trong Swift (async/await và actor), generic, và Swift Package Manager để quản lý thư viện phụ thuộc.
Câu hỏi thường gặp
Swift chỉ dành cho nền tảng của Apple thôi sao?
Không. Swift là mã nguồn mở và cũng chạy trên Linux và Windows, được dùng cho mã phía máy chủ và công cụ. Tuy nhiên, các framework ứng dụng như SwiftUI và UIKit chỉ có trên Apple.
Nên học Swift hay Objective-C?
Hãy học Swift. Đây là ngôn ngữ Apple khuyến nghị cho ứng dụng mới, và khi cần nó có thể gọi mã Objective-C sẵn có.
Struct và class trong Swift khác nhau thế nào?
Struct là kiểu giá trị, được sao chép khi gán hoặc truyền đi; class là kiểu tham chiếu, nên mọi biến cùng dùng chung một thể hiện. Class còn hỗ trợ kế thừa và deinitializer.
Dấu chấm hỏi sau một kiểu có nghĩa là gì?
Int? là một optional: nó chứa hoặc một Int hoặc nil. Bạn phải mở gói nó, chẳng hạn bằng if let, trước khi dùng giá trị.