You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中能否将属性名作为参数传入函数以避免代码重复?

问题解答:Swift中复用统计属性的实现方式

问题描述

我定义了如下的Stats类和Stat结构体:

class Stats {
    var stats: [Stat]
}
struct Stat {
    var id: UUID
    var countA: Int
    var countB: Int
    var countC: Int
    var totalAAttempts: Int
    var totalBAttempts: Int
    var totalCAttempts: Int
    // 其他属性
}

目前在Stats类中编写了大量重复的计算属性来统计百分比并格式化显示:

class Stats {
    var stats: [Stat]
    var countAPerc: Double {
        let totalA = stats.reduce(0) { total, stat in
            total + stat.countA
        }
        let totalAttempts = stats.reduce(0) { total, stat in
            total + stat.totalAAttempts
        }
        return Double(totalA) / Double(totalAttempts)
    }
    var countAPercDisplay: String {
        String(format: "%.1f", countAPerc * 100) + "%"
    }
    var countBPerc: Double {
        let totalB = stats.reduce(0) { total, stat in
            total + stat.countB
        }
        let totalAttempts = stats.reduce(0) { total, stat in
            total + stat.totalBAttempts
        }
        return Double(totalB) / Double(totalAttempts)
    }
    var countBPercDisplay: String {
        String(format: "%.1f", countBPerc * 100) + "%"
    }
    // 更多重复的计算属性
}

我希望通过将属性名作为参数传入函数的方式避免重复代码,比如编写如下复用函数:

func summarizeProperty(_ countProperty: PROPERTYNAME1, _ totalProperty: PROPERTYNAME2) -> Double {
    let totalCount = stats.reduce(0) { total, stat in
        total + stat.PROPERTYNAME1
    }
    let totalAttempts = stats.reduce(0) { total, stat in
        total + stat.PROPERTYNAME2
    }
    return Double(totalCount) / Double(totalAttempts)
}

func summarizedProperty(_ countProperty: PROPERTYNAME1, _ totalProperty: PROPERTYNAME2) -> String {
    let summarized = summarizeProperty(PROPERTYNAME1, PROPERTYNAME2)
    return String(format: "%.1f", summarized * 100) + "%"
}

并通过Text(summarizedProperty(countA, totalAAttempts))这样的方式调用,请问这种实现方式是否可行?

可行的实现方案

你想要的复用思路是对的,但直接传属性名在Swift中无法实现,需要用**键路径(KeyPath)**来传递属性的引用,这是Swift中复用属性访问逻辑的标准方式。

修改后的Stats类可以这样实现:

class Stats {
    var stats: [Stat]
    
    // 计算百分比的复用方法,接收两个KeyPath参数
    func summarizeProperty(countKey: KeyPath<Stat, Int>, totalKey: KeyPath<Stat, Int>) -> Double {
        let totalCount = stats.reduce(0) { $0 + $1[keyPath: countKey] }
        let totalAttempts = stats.reduce(0) { $0 + $1[keyPath: totalKey] }
        // 避免除以0的情况,防止出现NaN
        guard totalAttempts != 0 else { return 0 }
        return Double(totalCount) / Double(totalAttempts)
    }
    
    // 格式化显示的复用方法
    func summarizedPropertyDisplay(countKey: KeyPath<Stat, Int>, totalKey: KeyPath<Stat, Int>) -> String {
        let percentage = summarizeProperty(countKey: countKey, totalKey: totalKey)
        return String(format: "%.1f", percentage * 100) + "%"
    }
    
    // 可选:保留原有计算属性,内部调用复用方法,兼容旧代码
    var countAPercDisplay: String {
        summarizedPropertyDisplay(countKey: \.countA, totalKey: \.totalAAttempts)
    }
}

调用方式如下:

let stats = Stats(stats: [...]) // 初始化Stats实例
Text(stats.summarizedPropertyDisplay(countKey: \.countA, totalKey: \.totalAAttempts))
Text(stats.summarizedPropertyDisplay(countKey: \.countB, totalKey: \.totalBAttempts))

关键点说明

  • 键路径(KeyPath):\.countA是Stat结构体中countA属性的键路径,通过$1[keyPath: countKey]可以访问对应属性的值,完美实现属性引用的传递。
  • 健壮性处理:增加guard语句防止总尝试数为0时出现除以0的错误,避免返回NaN。
  • 兼容性:如果不想修改原有外部调用代码,可以保留原来的计算属性,内部复用新方法,实现无缝过渡。

内容的提问来源于stack exchange,提问作者Dovahkiin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 14:35:48