我是一名体验程序员,但我最近刚开始学习Swift(第4版)。
我发现很难做简单的任务,就像“给我第4 Character
个String
”。
我试着写这两个简单的函数:
// 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
作为参数?我错过了什么吗?
我知道可能有标准的库函数完全适合我上面的工作,但它只是一个演示。我的观点是知道如何编写适用于String
或Substring
的更复杂的函数。我怎么能这样做?
非常感谢你!
更新日期: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
在没有泛型的情况下工作正常?
答案 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
有三种相关类型:UTF8View
,UTF16View
和UnicodeScalarView
。这些可以是符合类型的任何内容,只要它们分别是UInt8
,UInt16
或UnicodeScalar
的集合。
我的观点是知道如何编写更复杂的函数来处理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 */ }