我一直在研究Exercism.io的Swift轨道,在将我的BinarySearchTree问题的解决方案重构为小代码之后,我注意到了一个似乎可以重构的模式。我认为答案是“不,你不能这样做”,但我认为值得一提。
typealias BinarySearchTree = BST
indirect enum BST< T: Comparable> {
case N( T, BST, BST )
case E
init( _ v: T ) { self = .N( v, .E, .E ) }
mutating func insert( _ n: T ) {
if case .N( let v, var l, var r ) = self {
if n <= v { l.insert( n ) } else { r.insert( n ) }
self = .N( v, l, r )
} else { self = .N( n, .E, .E ) }
}
var data: T? { if case let .N( v, _, _ ) = self { return v } else { return nil } }
var left: BST? { if case let .N( _, l, _ ) = self { return l } else { return nil } }
var right: BST? { if case let .N( _, _, r ) = self { return r } else { return nil } }
func allData() -> [ T ] { if case let .N( v, l, r ) = self { return l.allData() + [ v ] as [ T ] + r.allData() } else { return [ T ]() } }
}
我的重点是var
s data
,left
和right
。看看它们几乎是如何吐出彼此的图像?不是应该完成,而是可以完成:编写一个函数,通过一个参数接受T
或BST
,通过另一个参数接受元组位置({{1} }),并返回一个枚举分解的函数或闭包,并返回传入类型的捕获值?
我意识到我的代码的短名称和单行代码远远超过了愚蠢的地步。经过对这个初始解决方案的几次迭代后出现了,我认为你会同意它更具可读性,尽管模式不太明显:
Int
答案 0 :(得分:1)
这绝对可以简化,也可能应该是辅助功能:
private var vlr: (T, BST, BST)? {
switch self {
case let .N(v, l, r): return (v,l,r)
case .E: return nil
}
}
var data: T? { return vlr?.0 }
var left: BST? { return vlr?.1 }
var right: BST? { return vlr?.2 }
我在枚举上构建了这些类型的帮助程序,以便始终将关联数据转换为Optionals(在某些情况下作为公共方法)。
这也可以在allData
中使用,我可能会用这种方式编写(链式+
因在Swift中创建编译问题而臭名昭着,并且由于创建中间副本):
func allData() -> [ T ] {
if let (v, l, r) = vlr {
var result = l.allData()
result.append(v)
result.append(contentsOf: r.allData())
return result
}
return []
}