Swift参数包中的参数可以重写吗?

mwecs4sa  于 11个月前  发布在  Swift
关注(0)|答案(2)|浏览(163)

Parameter packs是Swift 5.9的一个很酷的新特性,但令人惊讶的是,似乎没有太多关于它们的讨论,我也没有在StackOverflow上看到这个问题的答案。

jexiocij

jexiocij1#

由于我还没有看到这个问题的答案,我想演示一下如何做到这一点会很有用。Swift 5.9没有内置的方法来覆盖参数包参数,但我们可以这样做,作为创建元组的副作用,如果我们不需要它,就丢弃元组结果。

func count<each T>(args: repeat each T) -> Int {
  var count = 0
  _ = (repeat (each args, count += 1))
  return count
}

字符串
上面的函数计算它的参数。不是很有用,但是如果我们稍微修改一下,我们会得到一个可以计算任何元组中元素数量的函数。

func count<each T>(tuple: (repeat each T)) -> Int {
  var count = 0
  _ = (repeat (each tuple, count += 1))
  return count
}


我们可以用这种技术做各种更高级的事情,通常使用辅助函数或闭包。例如,这里是我用Swift编写的解析器组合子包的代码。

private func tupleHelper<C: Collection, A>(
  _ parser: Parser<C, A>,
  _ source: C,
  _ range: inout Range<C.Index>
) throws -> A {
  switch parser(source, at: range.upperBound) {
  case .success(let state):
    range = state.range
    return state.output
  case .failure(let error):
    range = error.index..<error.index
    throw error
  }
}

public func tuple<C: Collection, each A>(
  _ parser: repeat Parser<C, each A>
) -> Parser<C, (repeat each A)> {
  .init { source, index in
    var range: Range<C.Index> = index..<index
    do {
      // This is where the magic happens.
      let result = try (repeat tupleHelper(each parser, source, &range))
      return .success(.init(output: result, range: index..<range.upperBound))
    } catch let error as ParseError<C> {
      return .failure(error)
    } catch {
      return .failure(.init(reason: .error(error), index: range.lowerBound))
    }
  }
}


这个combinator接受一个变量参数列表,其中包含了可能具有不同输出类型的解析器,并将它们作为元组返回。与任何解析器combinator框架一样,下一个解析器从上一个解析器停止的地方开始解析(假设它成功了)。helper函数使用inout参数修改range,并保持事情沿着进行。
主要的一点是,当Swift“执行”参数包时,它会按顺序调用每个元素,我们可以利用这一点来模拟迭代。

gab6jxml

gab6jxml2#

我也找到了一个方法。使用Mirror。你可以使用Mirror来遍历元组中的所有元素。

protocol TypeName {
    var typeName: String { get }
}

extension TypeName {
    var typeName: String {
        String(describing: Self.self)
    }
}

class Base: TypeName {}
final class Sub: Base {}
struct ST: TypeName {}

func printTypeName<each T: TypeName>(_ vals: repeat each T) {
    let tupName = (repeat (each vals).typeName)
    let m = Mirror(reflecting: tupName)
    for name in m.children.map(\.value) as! [String] {
        print(name)
    }
}
// or:
func printTypeName<each T: TypeName>(_ vals: repeat each T) {
    let m = Mirror(reflecting:  (repeat (each vals)))
    for case let val as any TypeName in m.children.map(\.value) {
        print(val.typeName)
    }
}

printTypeName(Sub(), ST(), Base())

/*
it prints:
Sub
ST
Base
*/

字符串

相关问题