我正在使用String
解析器,其中输入可以有各种格式,我事先并不知道正在使用哪种格式,所以我需要写一些灵活的东西。 / p>
第一步是检查前几个字符,我可以通过使用例如:
来检查func parse(input: String) -> String {
let result: String
if (input.hasPrefix("foo") {
result = doFoo(input)
}
else if (input.hasPrefix("bar") {
result = doBar(input)
}
else if (input.hasPrefix("baz") {
result = doBaz(input)
}
else {
result = doBasic(input)
}
return result
}
并且每个doXXX()
函数都有自己的解析代码,它也可以有多个选项,例如不同的分隔符等。
这很容易变成很多if-else代码,我想知道是否有一个更简单的方法来做到这一点。也许使用switch-case语句或其他东西?我可以使用枚举吗?
编辑:代码位于String
扩展名内。
答案 0 :(得分:2)
我将如何做到这一点:
// This pattern matching operator defines what it means to have a
// closure as a pattern. If the closure evaluates to true when called
// with `value` as an arg, then the `pattern` matches the `value`.
func ~=<T>(pattern: (T) -> Bool, value: T) -> Bool {
return pattern(value)
}
// This type alias is just here to make the next line a bit more readable.
// A `BoolInstanceMethod<T, U>` is a closure type that represents an unapplied
// instance method that ultimately returns a Bool.
// For example, `String.hasPrefix` has type `(String) -> (String) -> Bool`.
// The first argument, of type `T` (String, in this case) is the instance
// this method will be called on.
// Say we call this: String.hasPrefix("The quick brown fox").
// The result has type `(String) -> Bool`.
// It's equivalent to "The quick brown fox".hasPrefix.
// We then call the resulting closure with the arguement to hasPrefix
// For example: String.hasPrefix("The quick brown fox")("The")
// This has type `Bool`. It's the same as: "The quick brown fox".hasPrefix("The)
typealias BoolInstanceMethod<T, U> = (_ instance: T) -> (_ arg: U) -> Bool
// This function wraps a given instance method, in such a way as to reverse the
// order of the curried arguements. The given instance method is usually called as:
// Type.instanceMethod(instance)(arg), but this function allows you to swap it, to
// call it as: apply(Type.instanceMethod)(arg)(instance)
func apply<T, U>(instanceMethod: @escaping BoolInstanceMethod<T, U>) -> (_ arg: U) -> (_ instance: T) -> Bool {
return { arg in
return { instance in
return instanceMethod(instance)(arg)
}
}
}
// Dummy functions to satisfy the compiler
func doFoo(_: String) -> String { return "" }
func doBar(_: String) -> String { return "" }
func doBaz(_: String) -> String { return "" }
func doBasic(_: String) -> String { return "" }
func parse(input: String) -> String {
let result: String
// The predicate of choice is made, in this case, String.hasPrefix.
let hasPrefix = apply(instanceMethod: String.hasPrefix)
// The switch calls `~=` for every case, giving it hasPrefix(...) and "input"
// as args. The first case that makes `~=` yield `true` is executed.
switch input {
case hasPrefix("foo"): result = doFoo(input)
case hasPrefix("bar"): result = doBar(input)
case hasPrefix("baz"): result = doBaz(input)
default: result = doBasic(input)
}
return result
}
// You could also implement parse like this:
func parse2(input: String) -> String {
// You can save repeated application of the `input` parameter by doing it
// just once at the end (see the `return` of this func).
let action: (String) -> String
// The predicate of choice is made, in this case, String.hasPrefix.
let hasPrefix = apply(instanceMethod: String.hasPrefix)
// The switch calls `~=` for every case, giving it hasPrefix(...) and "input"
// as args. The first case that makes `~=` yield `true` is executed.
switch input {
case hasPrefix("foo"): action = doFoo
case hasPrefix("bar"): action = doBar
case hasPrefix("baz"): action = doBaz
default: action = doBasic
}
return action(input)
}