【Swift】Swift vs C# 核心语法对比指南

文章目录

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 没有隐式类型转换!IntDouble 不能直接运算,必须显式转换:

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 没有隐式类型转换 IntDouble 不能直接混算
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 并发
相关推荐
Vae_Mars6 小时前
C#中的delegate委托
开发语言·c#
公子小六11 小时前
基于.NET的Windows窗体编程之WinForms音频控件
windows·microsoft·c#·.net·音视频·winforms
绿浪198412 小时前
c# 结构体 能不能直接封送检测
开发语言·c#
新手unity自用笔记12 小时前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎
格林威13 小时前
C#图像像素放大:邻域平均、双线性插值实现像素放大的C#实现代码
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
枝枝在Coding14 小时前
我把 Codex 接进 SSH 后,才发现 Xterminal MCP 最难的是敢不敢让 Agent 动手
ssh·mcp
weixin_5316708916 小时前
Interlude起来:久坐提醒软件为什么需要登录?有没有完全本地运行的Mac休息提醒软件?
人工智能·macos·swift
2501_9160088917 小时前
Swift多环境配置:利用Scheme实现灵活的多环境管理
开发语言·ide·vscode·ios·个人开发·swift·敏捷流程
用户2986985301418 小时前
C# 实现 PowerPoint 多格式转换:图片、PDF 与 SVG 实战
c#·.net·svg
格林威20 小时前
C#图像处理:使用imagemagick实现像素放大水印转换等多种功能
android·开发语言·图像处理·人工智能·计算机视觉·c#·视觉检测