Swift实现AdditiveArithmetic时,静态变量无法调用实例成员
解决Electron中static var zero的实例成员访问错误
错误instance member 'dimen' cannot be used on type 'Electron<T>'的根本原因是:静态成员(static var zero)属于类型本身,而非某个具体实例,所以无法直接访问实例属性dimen。
你的Electron
方案一:改用静态方法创建全零实例(推荐)
放弃遵循AdditiveArithmetic协议(因为该协议的zero设计不适合需要维度的多维数组类型),改为提供一个接收维度参数的静态方法来创建全零数组:
// 移除Electron对AdditiveArithmetic的遵循,替换为自定义静态方法 extension Electron { public static func zero(dimen: [Int]) -> Electron<T> { return Electron(dimen, with: .repeating(0.0)) } // 保留原有的+、-等操作方法,添加维度检查避免崩溃 public static func + (lhs: Electron<T>, rhs: Electron<T>) -> Electron<T> { precondition(lhs.dimen == rhs.dimen, "维度不匹配的Electron无法相加") var output = lhs for (key, value) in lhs.energy { output.energy[key] = value + rhs.energy[key]! } return output } public static func - (lhs: Electron<T>, rhs: Electron<T>) -> Electron<T> { precondition(lhs.dimen == rhs.dimen, "维度不匹配的Electron无法相减") var output = lhs for (key, value) in lhs.energy { output.energy[key] = value - rhs.energy[key]! } return output } public static prefix func + (x: Electron<T>) -> Electron<T> { return x } }
调用时直接使用Electron.zero(dimen: [2,3])就能创建指定维度的全零数组,符合多维数组的使用习惯。
方案二:调整设计让维度成为类型的一部分(进阶)
如果你一定要遵循AdditiveArithmetic协议,可以把维度信息嵌入到泛型参数中,让类型本身携带维度信息:
// 定义表示维度的协议 protocol ShapeProtocol { static var dimensions: [Int] { get } } // 示例:定义2x3维度的Shape struct Shape2x3: ShapeProtocol { static var dimensions: [Int] = [2, 3] } // 修改Electron的泛型定义 public struct Electron<Shape: ShapeProtocol, T> where T: ExpressibleByFloatLiteral, T: AdditiveArithmetic { var energy: [[Int]: T] = [:] let dimen: [Int] = Shape.dimensions public init(with initializer: ElectronInitializer) { self.energy = [:] var curlay = [Int](repeating: 0, count: dimen.count) curlay[curlay.count-1] = -1 while true { var max: Int = -1 for x in 0..<curlay.count { if curlay[curlay.count-1-x] == dimen[curlay.count-1-x]-1 { max = curlay.count-1-x } else { break } } if max == 0 { break } else if max != -1 { for n in max..<curlay.count { curlay[n] = -1 } curlay[max-1] += 1 } curlay[curlay.count-1] += 1 print(curlay) energy[curlay] = { () -> T in switch initializer { case .repeating(let value): return T(value) // 替换强制转换,利用ExpressibleByFloatLiteral协议 case .random(let minimum, let maximum): return T(Double.random(in: minimum..<maximum)) } }() } } // 保留原有下标、setQuantum方法 subscript(_ coordinate: Int...) -> T { var convertList: [Int] = [] for conversion in coordinate { convertList.append(conversion) } return self.energy[convertList]! } public mutating func setQuantum(_ replace: T, at: [Int]) { self.energy[at]! = replace } } // 现在可以遵循AdditiveArithmetic协议 extension Electron: AdditiveArithmetic { public static var zero: Electron<Shape, T> { return Electron(with: .repeating(0.0)) } public static func + (lhs: Electron<Shape, T>, rhs: Electron<Shape, T>) -> Electron<Shape, T> { var output = lhs for (key, value) in lhs.energy { output.energy[key] = value + rhs.energy[key]! } return output } public static func - (lhs: Electron<Shape, T>, rhs: Electron<Shape, T>) -> Electron<Shape, T> { var output = lhs for (key, value) in lhs.energy { output.energy[key] = value - rhs.energy[key]! } return output } public static prefix func + (x: Electron<Shape, T>) -> Electron<Shape, T> { return x } }
这种方式下,Electron<Shape2x3, Double>.zero会自动创建2x3维度的全零数组,符合AdditiveArithmetic协议的要求,但设计复杂度更高。
额外代码优化建议
- 替换强制类型转换:初始化器中的
as! T会导致类型不匹配时崩溃,利用T的ExpressibleByFloatLiteral协议,改用T(value)实现安全转换。 - 避免强制解包:下标和加减方法中的
!会在key不存在时崩溃,建议添加维度检查或返回可选值。 - 简化坐标生成逻辑:当前生成所有坐标的循环可以用递归或更简洁的方式实现,降低代码复杂度。
内容的提问来源于stack exchange,提问作者Aadish Verma
相关产品推荐
相关产品推荐

