新手:接受String或子串的参数(可能使用StringProtocol)

时间:2017-09-28 07:05:09

标签: swift string substring swift4

我是一名体验程序员,但我最近刚开始学习Swift(第4版)。

我发现很难做简单的任务,就像“给我第4 CharacterString”。

我试着写这两个简单的函数:

// isHexCharacter returns whether a Character is hexadecimal or not
func isHexCharacter(_ c: Character) -> Bool {
    switch c {
    case "0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "A", "B", "C", "D", "E", "F":
        return true
    default:
        return false
    }
}

// isHexString returns whether a String (or Substring) consists
// entirely of hexadecimal characters
func isHexString(_ s: StringProtocol) -> Bool {
    for c in s {
        if !isHexCharacter(c) {
            return false
        }
    }
    return true
}

但编译器咬我:

demo.swift:20:23: error: protocol 'StringProtocol' can only be used
    as a generic constraint because it has Self or associated
    type requirements
func isHexString(_ s: StringProtocol) -> Bool {
                      ^
demo.swift:21:14: error: using 'StringProtocol' as a concrete type
conforming to protocol 'Sequence' is not supported
    for c in s {
             ^

我的问题是:

  • 我不懂编译器消息。他们的意思是什么?为什么我不能使用StringProtocol作为参数?我错过了什么吗?

  • 我知道可能有标准的库函数完全适合我上面的工作,但它只是一个演示。我的观点是知道如何编写适用于StringSubstring的更复杂的函数。我怎么能这样做?

非常感谢你!

更新日期:2017-09-28 08:05 UTC

正如@ martin-r所建议的那样,现在我改变了isHexString

func isHexString<S: StringProtocol>(_ s: S) -> Bool {
    for c in s {
        if !isHexCharacter(c) {
            return false
        }
    }
    return true
}

完美无缺!

但是,我尝试创建以下代码:

protocol Animal {
    func eat()
}

class Cat : Animal {
    func eat() {
        print("Meow")
    }
}

func animalEat(_ a: Animal) {
    a.eat()
}

var kitty = Cat()
animalEat(kitty)

我不知道为什么这样做没有错误。为什么函数animalEat在没有泛型的情况下工作正常?

1 个答案:

答案 0 :(得分:2)

  

我不懂编译器消息。他们是什么意思?

在Swift中,您可以通过为其提供“关联类型”来使用通用协议。例如

protocol Stack
{
    associated type Element

    func push(e: Element)
    func pop() -> Element
}

以上就像在Java interface Stack<T> ....

中使用通用接口一样

然而,在Swift中,只要在协议中放入关联类型,就不能再像普通类型那样对待它了,你必须开始跳过箍。所以你做不到

func myFunc(x: Stack<Int>)

你必须使它符合符合协议的类型

func myFunc<T: Stack>(x: T) where T.Element == Int // Not sure if the syntax is exactly right here

这是一种说同样的事情,但看起来更复杂。我不知道为什么会这样,这可能是一个实现问题,也可能与类型安全和类型推断有关。

问题是StringProtocol有三种相关类型:UTF8ViewUTF16ViewUnicodeScalarView。这些可以是符合类型的任何内容,只要它们分别是UInt8UInt16UnicodeScalar的集合。

  

我的观点是知道如何编写更复杂的函数来处理String或Substring。我怎么能这样做?

只需查找从字符串初始化的Int初始化程序,其中的签名类似于您所需的名称,即

convenience init?<S>(_ text: S, radix: Int = default) where S : StringProtocol

如果您的最终目标是获得十六进制数字,我会直接使用它。

guard let x = Int("0123F", radix: 16) else { /* Not a hex string */ }