简体   繁体   中英

Type 'MatchedValue' does not conform to protocol 'Decodable'

I have a struct that must conform to Codable protocol. However, I get the error:

Type 'MatchedValue' does not conform to protocol 'Decodable'**

How can I make String.Index conform to Codable? Thanks

struct MatchedValue: Codable {
    let value: String
    let range: Range<String.Index>
  }

Try using Int instead of String.Index.

First, extensions to get the position of an element or string as Int and the ability to use integer ranges:

extension StringProtocol {
    func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
    
    func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
    
    func substring(with range: Range<Int>) -> String? {
        guard range.lowerBound >= 0 && range.upperBound <= self.count else { return nil }
        
        let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
        let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound - range.lowerBound)

        return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
    }

    subscript(r: Range<Int>) -> String? { substring(with: r) }
    
    func substring(with range: ClosedRange<Int>) -> String? {
        guard range.lowerBound >= 0 && range.upperBound < self.count else { return nil }
        
        if range.lowerBound == range.upperBound { return "" }
        
        let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
        let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound + 1 - range.lowerBound)

        return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
    }
    
    subscript(r: ClosedRange<Int>) -> String? { substring(with: r) }
}

extension Collection {
    func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}

extension String.Index {
    func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}

Now you can use this new implementation:

let letters = "My string"
letters.count // 9

// get range
let lowerBound: Int? = letters.distance(of: "M")
let upperBound: Int? = letters.distance(of: "g")
let intRange: Range<Int> = lowerBound!..<upperBound!
let intClosedRange: ClosedRange<Int> = lowerBound!...upperBound!

// get substring
letters.substring(with: intRange)           // "My strin"
letters.substring(with: intClosedRange)     // "My string"
// or
letters[intRange]                           // "My strin"
letters[intClosedRange]                     // "My string"

I also include a comparison using String.Index and other tests.

// For comparison purposes only
let lowerIndex = letters.firstIndex(of: "M")
let upperIndex = letters.firstIndex(of: "g")
let range: Range<String.Index> = lowerIndex!..<upperIndex!
let closedRange: ClosedRange<String.Index> = lowerIndex!...upperIndex!
letters[range]                              // "My strin"
letters[closedRange]                        // "My string"

// Additional implementation tests
letters.substring(with: 3...5)  // "str"
letters.substring(with: 3..<5)  // "st"
letters.substring(with: 0...9)  // nil
letters.substring(with: 0..<9)  // "My string"
letters.substring(with: 2...2)  // ""
letters.substring(with: 2..<2)  // ""

Here is my gist .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM