swift-language by dpearson2699/swift-ios-skills
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swift-language针对 Swift 5.9+ 至 Swift 6 的核心 Swift 语言特性和现代语法模式。涵盖语言结构、类型系统特性、Codable、字符串和集合 API 以及格式化。关于并发(actor、async/await、Sendable),请参阅 swift-concurrency 技能。关于 SwiftUI 视图和状态管理,请参阅 swiftui-patterns。
Swift 5.9+ 允许 if 和 switch 作为返回值的表达式。使用它们直接进行赋值、返回或初始化。
// 从 if 表达式赋值
let icon = if isComplete { "checkmark.circle.fill" } else { "circle" }
// 从 switch 表达式赋值
let label = switch status {
case .draft: "Draft"
case .published: "Published"
case .archived: "Archived"
}
// 在返回位置工作
func color(for priority: Priority) -> Color {
switch priority {
case .high: .red
case .medium: .orange
case .low: .green
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
规则:
Swift 6+ 允许指定函数抛出的错误类型。
enum ValidationError: Error {
case tooShort, invalidCharacters, alreadyTaken
}
func validate(username: String) throws(ValidationError) -> String {
guard username.count >= 3 else { throw .tooShort }
guard username.allSatisfy(\.isLetterOrDigit) else { throw .invalidCharacters }
return username.lowercased()
}
// 调用者获得类型化错误——无需转换
do {
let name = try validate(username: input)
} catch {
// error 是 ValidationError,不是 any Error
switch error {
case .tooShort: print("Too short")
case .invalidCharacters: print("Invalid characters")
case .alreadyTaken: print("Taken")
}
}
规则:
throws(SomeError)。对于混合错误源,使用非类型化的 throws。throws(Never) 标记一个语法上抛出但实际上从不抛出的函数——在泛型上下文中很有用。throws(A) 和 throws(B) 的函数本身必须抛出涵盖两者的类型(或使用非类型化的 throws)。@resultBuilder 支持 DSL 风格的语法。SwiftUI 的 @ViewBuilder 是最常见的例子,但你可以为任何领域创建自定义构建器。
@resultBuilder
struct ArrayBuilder<Element> {
static func buildBlock(_ components: [Element]...) -> [Element] {
components.flatMap { $0 }
}
static func buildExpression(_ expression: Element) -> [Element] { [expression] }
static func buildOptional(_ component: [Element]?) -> [Element] { component ?? [] }
static func buildEither(first component: [Element]) -> [Element] { component }
static func buildEither(second component: [Element]) -> [Element] { component }
static func buildArray(_ components: [[Element]]) -> [Element] { components.flatMap { $0 } }
}
func makeItems(@ArrayBuilder<String> content: () -> [String]) -> [String] { content() }
let items = makeItems {
"Always included"
if showExtra { "Conditional" }
for name in names { name.uppercased() }
}
构建器方法: buildBlock(组合语句)、buildExpression(单个值)、buildOptional(不带 else 的 if)、buildEither(if/else)、buildArray(for..in)、buildFinalResult(可选的后期处理)。
自定义的 @propertyWrapper 类型封装了存储和访问模式。
@propertyWrapper
struct Clamped<Value: Comparable> {
private var value: Value
let range: ClosedRange<Value>
var wrappedValue: Value {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
var projectedValue: ClosedRange<Value> { range }
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
// 用法
struct Volume {
@Clamped(0...100) var level: Int = 50
}
var v = Volume()
v.level = 150 // 被限制为 100
print(v.$level) // 投影值:0...100
设计规则:
wrappedValue 是主要的 getter/setter。projectedValue(通过 $property 访问)提供元数据或绑定。@A @B var x 先应用外部包装器。some Protocol(不透明类型)调用者不知道具体类型,但编译器知道。底层类型在给定作用域内是固定的。
func makeCollection() -> some Collection<Int> {
[1, 2, 3] // 总是返回 Array<Int> —— 编译器知道具体类型
}
使用 some 用于:
func process(_ items: some Collection<Int>) —— 等价于泛型 <C: Collection<Int>>。any Protocol(存在类型)一个存在性容器,可以在运行时容纳任何符合协议的类型。具有动态分发和堆分配的开销。
func process(items: [any StringProtocol]) {
for item in items {
print(item.uppercased())
}
}
使用 some | 使用 any |
|---|---|
| 隐藏具体类型的返回类型 | 异构集合 |
| 函数参数(替代简单泛型) | 需要动态类型擦除 |
| 更好的性能(静态分发) | 协议有 Self 或关联类型要求需要擦除 |
经验法则: 默认使用 some。仅当需要异构集合或运行时类型灵活性时,才使用 any。
guard 强制执行前置条件并支持提前退出。它使主执行路径保持左对齐并减少嵌套。
func processOrder(_ order: Order?) throws -> Receipt {
// 解包可选值
guard let order else { throw OrderError.missing }
// 验证条件
guard order.items.isEmpty == false else { throw OrderError.empty }
guard order.total > 0 else { throw OrderError.invalidTotal }
// 布尔检查
guard order.isPaid else { throw OrderError.unpaid }
// 模式匹配
guard case .confirmed(let date) = order.status else {
throw OrderError.notConfirmed
}
return Receipt(order: order, confirmedAt: date)
}
最佳实践:
guard 处理前置条件,使用 if 处理分支逻辑。guard let a, let b else { return }。else 块必须退出作用域:return、throw、continue、break 或 fatalError()。guard let value else { ... }(Swift 5.7+)。Never 表示一个永不返回的函数。自 Swift 5.5+ 起,它符合所有协议(底类型)。
// 终止程序的函数
func crashWithDiagnostics(_ message: String) -> Never {
let diagnostics = gatherDiagnostics()
logger.critical("\(message): \(diagnostics)")
fatalError(message)
}
// 在泛型上下文中很有用
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
}
// Result<String, Never> —— 一个永远不会失败的结果
// Result<Never, Error> —— 一个永远不会成功的结果
// 详尽的 switch:不需要 default,因为 Never 没有 case
func handle(_ result: Result<String, Never>) {
switch result {
case .success(let value): print(value)
// 不需要 .failure case —— 编译器知道这是不可能的
}
}
Swift 5.7+ 的正则表达式构建器 DSL 提供了编译时检查、可读的模式。
import RegexBuilder
// 将 "2024-03-15" 解析为组件
let dateRegex = Regex {
Capture { /\d{4}/ }; "-"; Capture { /\d{2}/ }; "-"; Capture { /\d{2}/ }
}
if let match = "2024-03-15".firstMatch(of: dateRegex) {
let (_, year, month, day) = match.output
}
// 带转换的 TryCapture
let priceRegex = Regex {
"$"
TryCapture { OneOrMore(.digit); "."; Repeat(.digit, count: 2) }
transform: { Decimal(string: String($0)) }
}
何时使用构建器 vs. 字面量:
/pattern/):简单模式、熟悉正则表达式语法。/.../ 字面量。无需编写自定义解码器即可重命名键:
struct User: Codable {
let id: Int
let displayName: String
let avatarURL: URL
enum CodingKeys: String, CodingKey {
case id
case displayName = "display_name"
case avatarURL = "avatar_url"
}
}
处理不匹配的类型、默认值和转换:
struct Item: Decodable {
let name: String
let quantity: Int
let isActive: Bool
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
quantity = try container.decodeIfPresent(Int.self, forKey: .quantity) ?? 0
if let boolValue = try? container.decode(Bool.self, forKey: .isActive) {
isActive = boolValue
} else {
isActive = (try container.decode(String.self, forKey: .isActive)).lowercased() == "true"
}
}
enum CodingKeys: String, CodingKey { case name, quantity; case isActive = "is_active" }
}
将嵌套的 JSON 展平为扁平的 Swift 结构体:
// JSON: { "id": 1, "metadata": { "created_at": "...", "tags": [...] } }
struct Record: Decodable {
let id: Int
let createdAt: String
let tags: [String]
enum CodingKeys: String, CodingKey {
case id, metadata
}
enum MetadataKeys: String, CodingKey {
case createdAt = "created_at"
case tags
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
let metadata = try container.nestedContainer(
keyedBy: MetadataKeys.self, forKey: .metadata)
createdAt = try metadata.decode(String.self, forKey: .createdAt)
tags = try metadata.decode([String].self, forKey: .tags)
}
}
有关其他 Codable 模式(带关联值的枚举、日期策略、无键容器),请参阅 references/swift-patterns-extended.md。
优先使用这些现代 API 而非手动循环:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
// count(where:) —— Swift 5.0+,替代 .filter { }.count
let evenCount = numbers.count(where: { $0.isMultiple(of: 2) })
// contains(where:) —— 在第一个匹配项处短路
let hasNegative = numbers.contains(where: { $0 < 0 })
// first(where:) / last(where:)
let firstEven = numbers.first(where: { $0.isMultiple(of: 2) })
// String replacing() —— Swift 5.7+,返回新字符串
let cleaned = rawText.replacing(/\s+/, with: " ")
let snakeCase = name.replacing("_", with: " ")
// compactMap —— 从转换中解包可选值
let ids = strings.compactMap { Int($0) }
// flatMap —— 展平嵌套集合
let allTags = articles.flatMap(\.tags)
// Dictionary(grouping:by:)
let byCategory = Dictionary(grouping: items, by: \.category)
// reduce(into:) —— 高效累加
let freq = words.reduce(into: [:]) { counts, word in
counts[word, default: 0] += 1
}
使用 .formatted() 代替 DateFormatter/NumberFormatter。它是类型安全、本地化且简洁的。
// 日期
let now = Date.now
now.formatted() // "3/15/2024, 2:30 PM"
now.formatted(date: .abbreviated, time: .shortened) // "Mar 15, 2024, 2:30 PM"
now.formatted(.dateTime.year().month().day()) // "Mar 15, 2024"
now.formatted(.relative(presentation: .named)) // "yesterday"
// 数字
let price = 42.5
price.formatted(.currency(code: "USD")) // "$42.50"
price.formatted(.percent) // "4,250%"
(1_000_000).formatted(.number.notation(.compactName)) // "1M"
// 测量
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
distance.formatted(.measurement(width: .abbreviated)) // "5 km"
// 持续时间(Swift 5.7+)
let duration = Duration.seconds(3661)
duration.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
// 字节计数
Int64(1_500_000).formatted(.byteCount(style: .file)) // "1.5 MB"
// 列表
["Alice", "Bob", "Carol"].formatted(.list(type: .and)) // "Alice, Bob, and Carol"
解析: FormatStyle 也支持解析:
let value = try Decimal("$42.50", format: .currency(code: "USD"))
let date = try Date("Mar 15, 2024", strategy: .dateTime.month().day().year())
扩展 DefaultStringInterpolation 以支持特定领域的格式化。使用 """ 表示多行字符串(缩进相对于结束的 """)。有关自定义插值示例,请参阅 references/swift-patterns-extended.md。
some 可用时使用 any。 对于返回类型和参数,默认使用 some。any 有运行时开销并丢失类型信息。count(where:)、contains(where:)、compactMap、flatMap 代替手动迭代。DateFormatter 而非 FormatStyle。 .formatted() 更简单、类型安全,并自动处理本地化。decodeIfPresent 并提供默认值。guard let,以保持主执行路径在顶层。.replacing() 和 .contains()。var + append 构建集合。 优先使用 map、filter、compactMap 或 reduce(into:)。var 并修改它。some 而非 anyguard 处理前置条件,而非嵌套的 if let.formatted() 而非 DateFormatter/NumberFormatterCodingKeys 进行 API 键映射decodeIfPresent 并提供默认值String(describing:)Neverreferences/swift-patterns-extended.md每周安装数
338
仓库
GitHub 星标数
269
首次出现
Mar 8, 2026
安全审计
安装于
codex335
github-copilot332
kimi-cli332
gemini-cli332
cursor332
amp332
Core Swift language features and modern syntax patterns targeting Swift 5.9+ through Swift 6. Covers language constructs, type system features, Codable, string and collection APIs, and formatting. For concurrency (actors, async/await, Sendable), see the swift-concurrency skill. For SwiftUI views and state management, see swiftui-patterns.
Swift 5.9+ allows if and switch as expressions that return values. Use them to assign, return, or initialize directly.
// Assign from if expression
let icon = if isComplete { "checkmark.circle.fill" } else { "circle" }
// Assign from switch expression
let label = switch status {
case .draft: "Draft"
case .published: "Published"
case .archived: "Archived"
}
// Works in return position
func color(for priority: Priority) -> Color {
switch priority {
case .high: .red
case .medium: .orange
case .low: .green
}
}
Rules:
Swift 6+ allows specifying the error type a function throws.
enum ValidationError: Error {
case tooShort, invalidCharacters, alreadyTaken
}
func validate(username: String) throws(ValidationError) -> String {
guard username.count >= 3 else { throw .tooShort }
guard username.allSatisfy(\.isLetterOrDigit) else { throw .invalidCharacters }
return username.lowercased()
}
// Caller gets typed error -- no cast needed
do {
let name = try validate(username: input)
} catch {
// error is ValidationError, not any Error
switch error {
case .tooShort: print("Too short")
case .invalidCharacters: print("Invalid characters")
case .alreadyTaken: print("Taken")
}
}
Rules:
throws(SomeError) only when callers benefit from exhaustive error handling. For mixed error sources, use untyped throws.throws(Never) marks a function that syntactically throws but never actually does -- useful in generic contexts.throws(A) and throws(B) must itself throw a type that covers both (or use untyped throws).@resultBuilder enables DSL-style syntax. SwiftUI's @ViewBuilder is the most common example, but you can create custom builders for any domain.
@resultBuilder
struct ArrayBuilder<Element> {
static func buildBlock(_ components: [Element]...) -> [Element] {
components.flatMap { $0 }
}
static func buildExpression(_ expression: Element) -> [Element] { [expression] }
static func buildOptional(_ component: [Element]?) -> [Element] { component ?? [] }
static func buildEither(first component: [Element]) -> [Element] { component }
static func buildEither(second component: [Element]) -> [Element] { component }
static func buildArray(_ components: [[Element]]) -> [Element] { components.flatMap { $0 } }
}
func makeItems(@ArrayBuilder<String> content: () -> [String]) -> [String] { content() }
let items = makeItems {
"Always included"
if showExtra { "Conditional" }
for name in names { name.uppercased() }
}
Builder methods: buildBlock (combine statements), buildExpression (single value), buildOptional (if without else), buildEither (if/else), buildArray (for..in), buildFinalResult (optional post-processing).
Custom @propertyWrapper types encapsulate storage and access patterns.
@propertyWrapper
struct Clamped<Value: Comparable> {
private var value: Value
let range: ClosedRange<Value>
var wrappedValue: Value {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
var projectedValue: ClosedRange<Value> { range }
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
// Usage
struct Volume {
@Clamped(0...100) var level: Int = 50
}
var v = Volume()
v.level = 150 // clamped to 100
print(v.$level) // projected value: 0...100
Design rules:
wrappedValue is the primary getter/setter.projectedValue (accessed via $property) provides metadata or bindings.@A @B var x applies outer wrapper first.some Protocol (Opaque Type)The caller does not know the concrete type, but the compiler does. The underlying type is fixed for a given scope.
func makeCollection() -> some Collection<Int> {
[1, 2, 3] // Always returns Array<Int> -- compiler knows the concrete type
}
Use some for:
func process(_ items: some Collection<Int>) -- equivalent to a generic <C: Collection<Int>>.any Protocol (Existential Type)An existential box that can hold any conforming type at runtime. Has overhead from dynamic dispatch and heap allocation.
func process(items: [any StringProtocol]) {
for item in items {
print(item.uppercased())
}
}
Use some | Use any |
|---|---|
| Return type hiding concrete type | Heterogeneous collections |
| Function parameters (replaces simple generics) | Dynamic type erasure needed |
| Better performance (static dispatch) | Protocol has Self or associated type requirements you need to erase |
Rule of thumb: Default to some. Use any only when you need a heterogeneous collection or runtime type flexibility.
guard enforces preconditions and enables early exit. It keeps the happy path left-aligned and reduces nesting.
func processOrder(_ order: Order?) throws -> Receipt {
// Unwrap optionals
guard let order else { throw OrderError.missing }
// Validate conditions
guard order.items.isEmpty == false else { throw OrderError.empty }
guard order.total > 0 else { throw OrderError.invalidTotal }
// Boolean checks
guard order.isPaid else { throw OrderError.unpaid }
// Pattern matching
guard case .confirmed(let date) = order.status else {
throw OrderError.notConfirmed
}
return Receipt(order: order, confirmedAt: date)
}
Best practices:
guard for preconditions, if for branching logic.guard let a, let b else { return }.else block must exit scope: return, throw, continue, break, or fatalError().guard let value else { ... } (Swift 5.7+).Never indicates a function that never returns. It conforms to all protocols since Swift 5.5+ (bottom type).
// Function that terminates the program
func crashWithDiagnostics(_ message: String) -> Never {
let diagnostics = gatherDiagnostics()
logger.critical("\(message): \(diagnostics)")
fatalError(message)
}
// Useful in generic contexts
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
}
// Result<String, Never> -- a result that can never fail
// Result<Never, Error> -- a result that can never succeed
// Exhaustive switch: no default needed since Never has no cases
func handle(_ result: Result<String, Never>) {
switch result {
case .success(let value): print(value)
// No .failure case needed -- compiler knows it's impossible
}
}
Swift 5.7+ Regex builder DSL provides compile-time checked, readable patterns.
import RegexBuilder
// Parse "2024-03-15" into components
let dateRegex = Regex {
Capture { /\d{4}/ }; "-"; Capture { /\d{2}/ }; "-"; Capture { /\d{2}/ }
}
if let match = "2024-03-15".firstMatch(of: dateRegex) {
let (_, year, month, day) = match.output
}
// TryCapture with transform
let priceRegex = Regex {
"$"
TryCapture { OneOrMore(.digit); "."; Repeat(.digit, count: 2) }
transform: { Decimal(string: String($0)) }
}
When to use builder vs. literal:
/pattern/): simple patterns, familiarity with regex syntax./.../ literals inside builder blocks.Rename keys without writing a custom decoder:
struct User: Codable {
let id: Int
let displayName: String
let avatarURL: URL
enum CodingKeys: String, CodingKey {
case id
case displayName = "display_name"
case avatarURL = "avatar_url"
}
}
Handle mismatched types, defaults, and transformations:
struct Item: Decodable {
let name: String
let quantity: Int
let isActive: Bool
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
quantity = try container.decodeIfPresent(Int.self, forKey: .quantity) ?? 0
if let boolValue = try? container.decode(Bool.self, forKey: .isActive) {
isActive = boolValue
} else {
isActive = (try container.decode(String.self, forKey: .isActive)).lowercased() == "true"
}
}
enum CodingKeys: String, CodingKey { case name, quantity; case isActive = "is_active" }
}
Flatten nested JSON into a flat Swift struct:
// JSON: { "id": 1, "metadata": { "created_at": "...", "tags": [...] } }
struct Record: Decodable {
let id: Int
let createdAt: String
let tags: [String]
enum CodingKeys: String, CodingKey {
case id, metadata
}
enum MetadataKeys: String, CodingKey {
case createdAt = "created_at"
case tags
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
let metadata = try container.nestedContainer(
keyedBy: MetadataKeys.self, forKey: .metadata)
createdAt = try metadata.decode(String.self, forKey: .createdAt)
tags = try metadata.decode([String].self, forKey: .tags)
}
}
See references/swift-patterns-extended.md for additional Codable patterns (enums with associated values, date strategies, unkeyed containers).
Prefer these modern APIs over manual loops:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
// count(where:) -- Swift 5.0+, use instead of .filter { }.count
let evenCount = numbers.count(where: { $0.isMultiple(of: 2) })
// contains(where:) -- short-circuits on first match
let hasNegative = numbers.contains(where: { $0 < 0 })
// first(where:) / last(where:)
let firstEven = numbers.first(where: { $0.isMultiple(of: 2) })
// String replacing() -- Swift 5.7+, returns new string
let cleaned = rawText.replacing(/\s+/, with: " ")
let snakeCase = name.replacing("_", with: " ")
// compactMap -- unwrap optionals from a transform
let ids = strings.compactMap { Int($0) }
// flatMap -- flatten nested collections
let allTags = articles.flatMap(\.tags)
// Dictionary(grouping:by:)
let byCategory = Dictionary(grouping: items, by: \.category)
// reduce(into:) -- efficient accumulation
let freq = words.reduce(into: [:]) { counts, word in
counts[word, default: 0] += 1
}
Use .formatted() instead of DateFormatter/NumberFormatter. It is type-safe, localized, and concise.
// Dates
let now = Date.now
now.formatted() // "3/15/2024, 2:30 PM"
now.formatted(date: .abbreviated, time: .shortened) // "Mar 15, 2024, 2:30 PM"
now.formatted(.dateTime.year().month().day()) // "Mar 15, 2024"
now.formatted(.relative(presentation: .named)) // "yesterday"
// Numbers
let price = 42.5
price.formatted(.currency(code: "USD")) // "$42.50"
price.formatted(.percent) // "4,250%"
(1_000_000).formatted(.number.notation(.compactName)) // "1M"
// Measurements
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
distance.formatted(.measurement(width: .abbreviated)) // "5 km"
// Duration (Swift 5.7+)
let duration = Duration.seconds(3661)
duration.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
// Byte counts
Int64(1_500_000).formatted(.byteCount(style: .file)) // "1.5 MB"
// Lists
["Alice", "Bob", "Carol"].formatted(.list(type: .and)) // "Alice, Bob, and Carol"
Parsing: FormatStyle also supports parsing:
let value = try Decimal("$42.50", format: .currency(code: "USD"))
let date = try Date("Mar 15, 2024", strategy: .dateTime.month().day().year())
Extend DefaultStringInterpolation for domain-specific formatting. Use """ for multi-line strings (indentation is relative to the closing """). See references/swift-patterns-extended.md for custom interpolation examples.
any when some works. Default to some for return types and parameters. any has runtime overhead and loses type information.count(where:), contains(where:), compactMap, flatMap instead of manual iteration.DateFormatter instead of FormatStyle. .formatted() is simpler, type-safe, and handles localization automatically.some used over any where possibleguard used for preconditions, not nested if let.formatted() used instead of DateFormatter/NumberFormatterCodingKeys for API key mappingdecodeIfPresent with defaults for optional JSON fieldsreferences/swift-patterns-extended.mdWeekly Installs
338
Repository
GitHub Stars
269
First Seen
Mar 8, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex335
github-copilot332
kimi-cli332
gemini-cli332
cursor332
amp332
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装
竞争对手研究指南:SEO、内容、反向链接与定价分析工具
231 周安装
Azure 工作负载自动升级评估工具 - 支持 Functions、App Service 计划与 SKU 迁移
231 周安装
Kaizen持续改进方法论:软件开发中的渐进式优化与防错设计实践指南
231 周安装
软件UI/UX设计指南:以用户为中心的设计原则、WCAG可访问性与平台规范
231 周安装
Apify 网络爬虫和自动化平台 - 无需编码抓取亚马逊、谷歌、领英等网站数据
231 周安装
llama.cpp 中文指南:纯 C/C++ LLM 推理,CPU/非 NVIDIA 硬件优化部署
231 周安装
decodeIfPresent with defaults for optional or missing keys.guard let for preconditions to keep the happy path at the top level..replacing() and .contains() before reaching for Regex.var + append in a loop. Prefer map, filter, compactMap, or reduce(into:).var and mutating it.String(describing:)Never used appropriately in generic contexts