类型“String.Index”不符合协议“IntegerLiteralConvertible”

Posted

技术标签:

【中文标题】类型“String.Index”不符合协议“IntegerLiteralConvertible”【英文标题】:Type 'String.Index' does not conform protocol 'IntegerLiteralConvertible' 【发布时间】:2014-07-22 06:46:56 【问题描述】:

使用 Beta 3 一切正常,现在我收到一个奇怪的错误,我不知道如何修复它。尝试了所有类似问题的解决方案。

这是我的代码:

if !name.isEmpty 
        var splitted: [String] = name.componentsSeparatedByString(" ")

        for curPart in splitted 
            if !curPart.isEmpty 
                acronym += curPart.substringToIndex(1) //Error
            
        
        if (acronym as NSString).length > 2 
            acronym = acronym.substringToIndex(2) //Error
        
    

两条标记的行都给了我同样的错误:

有人可以帮助我吗?还是 Beta 4 被窃听了? 谢谢!

【问题讨论】:

【参考方案1】:

在 beta 4 中,Swift 的 String.Index 处理再次发生了变化——当需要 String.Index 时,您现在无法提供 Int。处理它的方法是使用advance 方法创建您需要的String.Index

if !name.isEmpty 
    var splitted: [String] = name.componentsSeparatedByString(" ")

    for curPart in splitted 
        if !curPart.isEmpty 
            acronym += curPart.substringToIndex(advance(curPart.startIndex, 1))
        
    
    if countElements(acronym) > 2 
        acronym = acronym.substringToIndex(advance(acronym.startIndex, 2))
    

这一切都是基于确保正确处理 Unicode 字符串 - 因为不同的 Unicode 字符可以有不同的大小,纯整数索引会隐藏字符串不是随机访问的事实。

【讨论】:

感谢您的解决方案!它编译并且似乎工作!谢谢。我也认为这会在 swift 1.0 之前改变 “这一切都是基于确保正确处理 Unicode 字符串 - 因为不同的 Unicode 字符可以有不同的大小,纯整数索引会隐藏字符串不是随机访问的事实。”。我认为通过使用恰好是一个 unicode 字符的 Charcater 类型(而不是例如字节)来快速解决这个问题,而 swift Strings 可以被认为是这样的数组吗?访问字符串的第 n 个(unicode)字符的方式是什么? 不,每个Character 都是字符串中的单个可见 字符,可以由一个、两个或多个代码点组成。例如,?‍?‍?‍?我认为是七。 如果您正在寻找一个确实使用 Int 来获取您可能想要的所有子字符串的扩展,请试试这个:***.com/questions/24044851/… "访问字符串的第 n 个(unicode)字符的方式是什么?" -- Swift 的理念是,您应该在编写代码时感受到 Unicode 字符串处理的运行时成本。昂贵的操作写起来很痛苦。【参考方案2】:

Swift 的字符串组件和迭代的概念在 Beta 4 中发生了变化。从the guide,我们看到:

Swift 的 Character 类型的每个实例都代表一个扩展的字素簇。扩展字素簇是一个或多个 Unicode 标量的序列,这些标量(组合时)产生单个人类可读字符。

这有一些有趣的副作用:

let str1 = "abc"
let str2 = "\u20DDdef"

countElements(str1)      // 3 
countElements(str2)      // 4
countElements(str1+str2) // 6 ≠ 3+4 !!!

那是因为 c\u20DD 组合成 c⃝。另请注意,我们使用的是countElements。为了算出字符串的长度,Swift 实际上必须遍历整个字符串并找出实际的字素划分在哪里,因此需要 O(n) 时间。

我们还可以看到不同编码的效果:

Array((str1+str2).utf8)  // [97, 98, 99, 226, 131, 157, 100, 101, 102]
Array((str1+str2).utf16) // [97, 98, 99, 8413, 100, 101, 102]

另一个问题,正如您的错误所说,StringIndexType 不再可以从整数文字转换:您不能通过指定偏移量对字符串执行随机访问。相反,您可以使用startIndexadvance 在字符串中向前移动一段距离,例如str[str.startIndex]str[advance(str.startIndex, distance)]

或者您可以同时定义自己的辅助函数:

func at<C: Collection>(c: C, i: C.IndexType.DistanceType) -> C.GeneratorType.Element 
    return c[advance(c.startIndex, i)]


func take<C: protocol<Collection, Sliceable>>(c: C, n: C.IndexType.DistanceType) -> C.SliceType 
    return c[c.startIndex..<advance(c.startIndex, n)]


at(str1+str2, 3)   // d

take(str1+str2, 2) // ab

显然,在未来的更新中可能(并且可能会)进行一些改进。您可能想file a bug 提出您的疑虑。从长远来看,正确支持字素集群可能是一个不错的决定,但同时它也会让字符串访问变得更加痛苦。

【讨论】:

好的,现在我知道幕后发生了什么:D 谢谢!【参考方案3】:

对于 Swift 2.0

使用上面的例子:

curPart.substringToIndex(curPart.startIndex.advancedBy(1)) 

【讨论】:

以上是关于类型“String.Index”不符合协议“IntegerLiteralConvertible”的主要内容,如果未能解决你的问题,请参考以下文章

尝试符合可等式泛型 Set 时,类型“任何”不符合协议“等式”

迅速覆盖属性

无法转换类型“Range<Int>?”的值到预期的参数类型'Range<String.Index>?

符合 Swift 协议的泛型类型

符合自定义协议的通用函数 - Swift

类型“ViewController”不符合协议