文章目录
- [Swift vs C# 语法对比指南](# 语法对比指南)
-
- 一、变量与常量
- 二、基本数据类型
- [三、Optional(Swift 最核心的区别)](#三、Optional(Swift 最核心的区别))
- 四、字符串操作
- 五、集合类型
- 六、流程控制
-
- [if / else](#if / else)
- [switch(Swift 强大得多)](#switch(Swift 强大得多))
- [for 循环](#for 循环)
- [while / repeat](#while / repeat)
- 七、函数
-
- [返回元组 / 多返回值](#返回元组 / 多返回值)
- [八、闭包 vs Lambda](#八、闭包 vs Lambda)
- 九、类与结构体
-
- [类(class)--- 引用类型](#类(class)— 引用类型)
- [结构体(struct)--- 值类型](#结构体(struct)— 值类型)
- 十、枚举
- [十一、协议 vs 接口](#十一、协议 vs 接口)
- 十二、泛型
- 十三、扩展(Extension)
- 十四、错误处理
- 十五、内存管理
- 十六、属性
- 十七、并发
- 十八、快速对照表
- [十九、最容易踩的坑 ⚠️](#十九、最容易踩的坑 ⚠️)
- 二十、建议的练习方式

Swift vs C# 语法对比指南
作为 C# 开发者转 Swift,你会发现两者有很多相似之处(都是强类型、面向对象、现代语言),但细节差异不少。以下逐项对比:
一、变量与常量
| 概念 | C# | Swift |
|---|---|---|
| 可变变量 | int x = 10; |
var x = 10 |
| 不可变常量 | const int x = 10; / readonly |
let x = 10 |
| 类型推断 | var x = 10; |
let x = 10(自动推断为 Int) |
| 显式类型 | int x = 10; |
let x: Int = 10 |
csharp
// C#
var name = "Alice";
const int age = 25;
swift
// Swift
let name = "Alice" // 不可变
var age = 25 // 可变
let score: Double = 9.5 // 显式类型
⚠️ Swift 中
let用得远比var多,编译器鼓励不可变优先。
二、基本数据类型
| C# | Swift | 说明 |
|---|---|---|
int |
Int |
整数 |
double |
Double |
双精度浮点 |
float |
Float |
单精度浮点 |
bool |
Bool |
布尔 |
string |
String |
字符串 |
char |
Character |
单字符 |
csharp
// C#
int a = 10;
bool flag = true;
string s = "hello";
swift
// Swift
let a: Int = 10
let flag: Bool = true
let s: String = "hello"
💡 Swift 没有隐式类型转换!
Int和Double不能直接运算,必须显式转换:
swift
let x: Int = 5
let y: Double = 2.5
let result = Double(x) + y // 必须转换
C# 中
int + double会隐式转换,Swift 不会。
三、Optional(Swift 最核心的区别)
C# 用 Nullable<T> 或引用类型默认可为 null;Swift 用 Optional 系统:
csharp
// C#
string? name = null;
int? age = null;
swift
// Swift
var name: String? = nil // Optional<String>
var age: Int? = nil // Optional<Int>
let city: String = "Beijing" // 不能赋 nil,非可选
解包方式对比
csharp
// C# - null 检查
if (name != null) {
Console.WriteLine(name.Length);
}
// 或
Console.WriteLine(name?.Length);
// 或
var len = name ?? "default";
swift
// Swift - 可选解包
// 1. if-let(最安全)
if let name = name {
print(name.count)
}
// 2. guard-let(提前退出)
func greet(name: String?) {
guard let n = name else {
print("no name")
return
}
print(n.count)
}
// 3. 可选链(类似 C# 的 ?.)
let len = name?.count
// 4. 空合运算符(类似 C# 的 ??)
let result = name ?? "default"
// 5. 强制解包(危险,类似直接访问 null)
let val = name! // 如果是 nil 会崩溃
🔑 核心区别 :C# 引用类型默认可为 null,编译器不强制检查;Swift 默认不可为 nil ,必须显式声明
?,编译器强制你处理。
四、字符串操作
csharp
// C#
string s = "Hello, World";
int len = s.Length;
string upper = s.ToUpper();
bool contains = s.Contains("World");
string sub = s.Substring(0, 5);
string interpolated = $"Name: {name}, Age: {age}";
swift
// Swift
let s = "Hello, World"
let len = s.count
let upper = s.uppercased()
let contains = s.contains("World")
let sub = String(s.prefix(5))
let interpolated = "Name: $name), Age: $age)"
⚠️ Swift 字符串没有下标索引(
s[0]不行),因为 Unicode 字符宽度不同,需要用String.Index。
五、集合类型
| C# | Swift | 说明 |
|---|---|---|
List<int> |
[Int] 或 Array<Int> |
数组 |
Dictionary<string, int> |
[String: Int] |
字典 |
HashSet<int> |
Set<Int> |
集合 |
csharp
// C#
var list = new List<int> { 1, 2, 3 };
var dict = new Dictionary<string, int> { ["age"] = 25 };
list.Add(4);
var val = dict["age"];
swift
// Swift
var list = [1, 2, 3] // 自动推断为 [Int]
var dict: [String: Int] = ["age": 25]
list.append(4)
let val = dict["age"] // 返回 Int?(Optional!)
let val2 = dict["age", default: 0] // 提供默认值
💡 Swift 字典取值返回 Optional,因为 key 可能不存在。
六、流程控制
if / else
csharp
// C#
if (x > 10) { }
else if (x > 5) { }
else { }
swift
// Swift --- 几乎一样,但括号可省略
if x > 10 { }
else if x > 5 { }
else { }
switch(Swift 强大得多)
csharp
// C#
switch (day) {
case 1: Console.WriteLine("Mon"); break;
case 2: Console.WriteLine("Tue"); break;
default: break;
}
swift
// Swift --- 不需要 break,支持模式匹配
switch day {
case 1:
print("Mon")
case 2...5: // 范围匹配!
print("Weekday")
case 6, 7: // 多值
print("Weekend")
default:
print("Invalid")
}
// 更强大:where 子句
let point = (3, 4)
switch point {
case let (x, y) where x == y:
print("on diagonal")
case (0, 0):
print("origin")
default:
print("somewhere")
}
for 循环
csharp
// C#
for (int i = 0; i < 10; i++) { }
foreach (var item in list) { }
swift
// Swift --- 没有传统 for(;;) 循环
for i in 0..<10 { } // 0到9(半开区间)
for i in 0...10 { } // 0到10(闭区间)
for item in list { } // 遍历
for (index, item) in list.enumerated() { } // 带索引
while / repeat
csharp
// C#
while (x > 0) { x--; }
do { x--; } while (x > 0);
swift
// Swift
while x > 0 { x -= 1 }
repeat { x -= 1 } while x > 0 // do-while 改名 repeat-while
七、函数
csharp
// C#
int Add(int a, int b) { return a + b; }
void Greet(string name, bool formal = false) { }
int Sum(params int[] nums) { }
swift
// Swift --- 有参数标签(外部名)
func add(_ a: Int, _ b: Int) -> Int { return a + b }
func greet(name: String, formal: Bool = false) { }
func sum(_ nums: Int...) -> Int { } // 可变参数
// 调用时的区别
add(3, 5) // _ 表示省略外部名
greet(name: "Alice", formal: true) // 必须写参数标签!
sum(1, 2, 3, 4)
🔑 关键区别 :Swift 函数有参数标签(外部名),调用时必须写出来:
swift
func move(from start: Int, to end: Int) { }
move(from: 1, to: 5) // 调用时必须写 from: 和 to:
返回元组 / 多返回值
csharp
// C# 7+
(int x, int y) GetPoint() => (1, 2);
swift
// Swift
func getPoint() -> (x: Int, y: Int) { return (1, 2) }
let p = getPoint()
print(p.x) // 1
八、闭包 vs Lambda
csharp
// C# Lambda
Func<int, int> square = x => x * x;
var result = list.Where(x => x > 3).Select(x => x * 2);
swift
// Swift 闭包
let square: (Int) -> Int = { x in x * x }
let result = list.filter { $0 > 3 }.map { $0 * 2 }
| C# | Swift | 说明 |
|---|---|---|
x => x * x |
{ x in x * x } |
基本写法 |
(x, y) => x + y |
{ x, y in x + y } |
多参数 |
x => x |
{ $0 } |
简写:$0, $1 代表参数 |
Func<int,int> |
(Int) -> Int |
类型声明 |
swift
// 尾随闭包(Swift 特色,非常常用)
let sorted = names.sorted { $0 < $1 }
let sorted2 = names.sorted(by: <) // 运算符直接当函数传
// 高阶函数
let evens = numbers.filter { $0 % 2 == 0 }
let doubled = numbers.map { $0 * 2 }
let sum = numbers.reduce(0) { $0 + $1 }
let flat = nested.compactMap { $0 } // 过滤 nil 并解包
九、类与结构体
类(class)--- 引用类型
csharp
// C#
class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age) {
Name = name;
Age = age;
}
public override string ToString() => $"Person: {Name}";
}
swift
// Swift
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
// 没有 override 关键字就不能重写
var description: String {
return "Person: $name)"
}
}
结构体(struct)--- 值类型
csharp
// C# struct
struct Point {
public int X;
public int Y;
}
swift
// Swift struct --- 使用更广泛!
struct Point {
var x: Int
var y: Int
// 自动获得 memberwise init
// let p = Point(x: 1, y: 2)
mutating func moveBy(dx: Int, dy: Int) {
x += dx // 修改自身属性需要 mutating
y += dy
}
}
🔑 核心区别:
- C# 中 struct 很少用,绝大多数用 class
- Swift 中 struct 是首选,只有需要共享引用时才用 class
- Swift struct 可以有方法、协议、扩展,功能几乎和 class 一样
十、枚举
csharp
// C#
enum Direction { Up, Down, Left, Right }
swift
// Swift 枚举强大得多!
// 基本
enum Direction { case up, down, left, right }
// 带关联值(C# 没有的)
enum Result {
case success(data: String)
case failure(code: Int, message: String)
}
let r = Result.success(data: "OK")
// 带原始值
enum HTTPCode: Int {
case ok = 200
case notFound = 404
}
// 带方法
enum Coin: Double {
case penny = 0.01
case quarter = 0.25
func description() -> String {
return "Coin worth $rawValue)"
}
}
十一、协议 vs 接口
csharp
// C# 接口
interface IDrawable {
void Draw();
string Name { get; }
}
class Circle : IDrawable {
public string Name => "Circle";
public void Draw() { Console.WriteLine("Drawing circle"); }
}
swift
// Swift 协议
protocol Drawable {
func draw()
var name: String { get }
}
struct Circle: Drawable {
let name = "Circle"
func draw() { print("Drawing circle") }
}
// 协议可以有默认实现!(通过 extension)
extension Drawable {
func draw() {
print("Default drawing")
}
}
💡 Swift 协议 ≈ C# 接口 + 默认接口方法,但更灵活,struct/enum/class 都能遵循。
十二、泛型
csharp
// C#
T Max<T>(T a, T b) where T : IComparable<T> {
return a.CompareTo(b) > 0 ? a : b;
}
swift
// Swift
func max<T: Comparable>(_ a: T, _ b: T) -> T {
return a > b ? a : b
}
| C# | Swift | 说明 |
|---|---|---|
where T : IComparable<T> |
<T: Comparable> |
约束 |
where T : class |
AnyObject |
引用类型约束 |
default(T) |
无直接等价 | Swift 用 Optional 代替 |
十三、扩展(Extension)
csharp
// C# 扩展方法(只能在静态类中)
public static class StringExt {
public static int WordCount(this string s) {
return s.Split(' ').Length;
}
}
"hello world".WordCount();
swift
// Swift 扩展 --- 更强大,可以加计算属性、方法、协议
extension String {
var wordCount: Int {
return split(separator: " ").count
}
func repeated(_ times: Int) -> String {
return String(repeating: self, count: times)
}
}
"hello world".wordCount // 2
"ha".repeated(3) // "hahaha"
// 甚至给 Int 加扩展
extension Int {
var isEven: Bool { self % 2 == 0 }
var times: [Int] { Array(0..<self) }
}
5.isEven // false
3.times // [0, 1, 2]
十四、错误处理
csharp
// C#
try {
int result = int.Parse(input);
} catch (FormatException ex) {
Console.WriteLine(ex.Message);
} finally {
// cleanup
}
swift
// Swift
enum ParseError: Error {
case invalidFormat
case outOfRange(min: Int, max: Int)
}
func parse(_ input: String) throws -> Int {
guard let val = Int(input) else {
throw ParseError.invalidFormat
}
return val
}
// 调用
do {
let result = try parse("abc")
} catch ParseError.invalidFormat {
print("Bad format")
} catch {
print("Other error: $error)")
}
// 简写
let result = try? parse("123") // 返回 Int?,失败为 nil
let result2 = try! parse("123") // 强制,失败崩溃
十五、内存管理
| C# | Swift |
|---|---|
| GC(垃圾回收) | ARC(引用计数) |
| 无需手动管理 | 需要注意循环引用 |
弱引用:WeakReference |
weak var / unowned |
csharp
// C# --- GC 自动回收
class ViewModel {
public event Action OnChange; // GC 处理
}
swift
// Swift --- 必须手动打破循环引用
class ViewModel {
var onChange: (() -> Void)?
func setup() {
// ❌ 循环引用!self 被闭包强引用
onChange = { print(self.name) }
// ✅ 用 [weak self] 打破
onChange = { [weak self] in
guard let self = self else { return }
print(self.name)
}
}
deinit { // 析构函数(类似 C# 的 ~ClassName / IDisposable)
print("ViewModel released")
}
}
⚠️ 这是从 C# 转 Swift 最容易踩的坑:闭包捕获 self 导致内存泄漏。
十六、属性
csharp
// C#
class User {
public string Name { get; set; }
public int Age { get; private set; }
public string DisplayName => $"{Name} ({Age})"; // 计算属性
private string _email;
public string Email {
get => _email;
set { _email = value.ToLower(); } // 自定义 setter
}
}
swift
// Swift
class User {
var name: String = ""
private(set) var age: Int = 0
var displayName: String { // 计算属性
return "$name) ($age))"
}
var email: String = "" {
didSet { // 属性观察器(C#没有)
email = email.lowercased()
}
}
var score: Int = 0 {
willSet { print("即将变为 $newValue)") }
didSet { print("从 $oldValue) 变来") }
}
}
💡 Swift 的
willSet/didSet属性观察器非常好用,C# 没有对应语法。
十七、并发
csharp
// C# async/await
async Task<string> FetchDataAsync() {
var response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
swift
// Swift async/await(几乎一样!)
func fetchData() async throws -> String {
let (data, _) = try await URLSession.shared.data(from: url)
return String(data: data, encoding: .utf8) ?? ""
}
// 调用
Task {
let result = try await fetchData()
print(result)
}
// 并行执行
async let a = fetchUser()
async let b = fetchPosts()
let (user, posts) = try await (a, b)
| C# | Swift | 说明 |
|---|---|---|
Task<T> |
async -> T |
异步函数 |
await |
await |
等待 |
Task.WhenAll |
async let / TaskGroup |
并行 |
lock / Monitor |
actor |
线程安全 |
swift
// Actor(C# 没有直接对应,类似线程安全的类)
actor BankAccount {
var balance: Double = 0
func deposit(_ amount: Double) {
balance += amount // 自动线程安全
}
}
十八、快速对照表
| 概念 | C# | Swift |
|---|---|---|
| 空值 | null |
nil |
| 空判断 | ?. |
?. |
| 空合并 | ?? |
?? |
| 字符串插值 | $"{x}" |
"$x)" |
| 类型转换 | (int)obj / as |
as? / as! / as |
| 模式匹配 | is / switch |
if case / switch / if let |
| 命名空间 | namespace |
无(用模块/module) |
| 打印 | Console.WriteLine() |
print() |
| 入口 | Main() |
@main / 顶层代码 |
| 包管理 | NuGet | SPM / CocoaPods |
| 接口 | interface |
protocol |
| 委托/事件 | delegate / event |
闭包 / Combine |
| LINQ | .Where().Select() |
.filter{}.map{} |
| 析构 | ~Class() / IDisposable |
deinit |
| 静态成员 | static |
static(类中用 class) |
| 访问修饰 | public/private/protected/internal |
public/private/fileprivate/internal/open |
十九、最容易踩的坑 ⚠️
| # | 坑 | 说明 |
|---|---|---|
| 1 | 没有隐式类型转换 | Int 和 Double 不能直接混算 |
| 2 | Optional 无处不在 | 字典取值、类型转换都返回 Optional |
| 3 | 闭包捕获 self | 必须 [weak self],否则内存泄漏 |
| 4 | struct 是值类型 | 赋值/传参是拷贝,和 C# class 行为不同 |
| 5 | 没有 for(int i=0;...) |
用 for i in 0..<n |
| 6 | switch 不需要 break | 不会 fall through |
| 7 | 函数参数标签 | 调用时必须写外部参数名 |
| 8 | 没有 GC | 靠 ARC,循环引用需手动处理 |
二十、建议的练习方式
1. 把你熟悉的 C# 小程序用 Swift 重写一遍
2. 重点练习 Optional 处理(if-let / guard-let)
3. 用 struct + protocol 替代你习惯的 class + interface
4. 写几个闭包操作数组(filter/map/reduce)
5. 写一个 async 网络请求,体会 Swift 并发