简体   繁体   中英

Unresolved identifier error in swift function with nested if loop

I'm currently teaching myself Swift coming from a background of Python recently and Visual Basic originally. I would describe myself as competent in those codes but a novice in Swift. I'm trying to write a function that will return a set number of digits from either the start or end of a long integer. My chosen method has been to convert the integer to a string and then use the prefix or suffix command.

Whilst I can get the function to work if it has no flow control and uses either prefix or suffix (first lot of code), when I try to write one function that does both I get an unresolved identifier error on the turnStringToInteger variable (second lot of code). I'm pretty sure this is because the variable lives within the if {} but if I declare it outside of the if loop (hashed out) this also errors. I appreciate this will have a really simple answer but how do I use the return correctly with a nested if loop?

This works...

//Function to Trim Integer (Prefix Only)
func integerTrim(integer:Int, trimLength:Int) -> Int {
    var strFromInteger = String(integer)
    var trimmedString = strFromInteger.prefix(trimLength)
    var intFromString = Int(trimmedString) ?? 0
    return intFromString
}

//Declare Input
var inputInt = 12345678910

//Call Function
var result = integerTrim(integer: inputInt, trimLength: 4)

//Print Results
print(inputInt)
print(result)

This doesn't...!

//Function to trim integer prefix or suffix
func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
    var typeID = type
    //var turnStringToInteger: Int
    if typeID == "P" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.prefix(trimLength)
        var turnStringToIngeger = Int(trimmedString) ?? 0
    }
    else if typeID == "S" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.suffix(trimLength)
        var turnStringToIngeger = Int(trimmedString) ?? 0
    }
    return turnStringToInteger
}

//Declare Input
var inputInt = 53737363856453

//Call Function
var result = integerTrim(integer: inputInt, type: "P", trimLength: 4)

//Print Results
print(inputInt)
print(result)

As I am self taught I appreciate I may also not be using best practices. I really want to learn to do this properly so if I am going about all of this the wrong way to begin with I would be equally happy to hear other approaches. For example I did consider turning the integer to an array and then creating the trimmed integer from positions within this array. Would this be more elegant?

If you want to access the variable outside of the scope where it is assigned, you need to declare it in the outer scope.

If you do that without assigning it an initial value, you get an error: variable 'turnStringToInteger' used before being initialized . That happens because Swift sees a path in which turnStringToInteger never gets assigned a value (imagine what happens if "X" is passed in for type ).

So your real issue is the use of String as the type for type . It would be better to use an enum that expresses exactly what you want:

enum TrimType {
    case prefix, suffix
}

func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {

    let typeID = type
    var turnStringToInteger: Int

    switch typeID {
    case .prefix:
        let turnIntegerToString = String(integer)
        let trimmedString = turnIntegerToString.prefix(trimLength)
        turnStringToInteger = Int(trimmedString) ?? 0
    case .suffix:
        let turnIntegerToString = String(integer)
        let trimmedString = turnIntegerToString.suffix(trimLength)
        turnStringToInteger = Int(trimmedString) ?? 0
    }

    return turnStringToInteger
}

Now there are only 2 possibilities for type and the switch handles both.

You call it like this:

let result = integerTrim(integer: inputInt, type: .prefix, trimLength: 4)

... after a little refactoring:

func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {

    let turnIntegerToString = String(integer)
    let trimmedString: Substring

    switch type {
    case .prefix:
        trimmedString = turnIntegerToString.prefix(trimLength)
    case .suffix:
        trimmedString = turnIntegerToString.suffix(trimLength)
    }

    return Int(trimmedString) ?? 0

}

There's a few ways to do this. The root of the problem is your turnIntegerToString lifetime is within the braces - and the return is outside the braces.

func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
    var typeID = type
    var turnStringToInteger: Int = 0
    // If you don't want to assign it to zero (your nil coalesce implies we can) - instead use...
    // var turnStringToInteger: Int! // However - this can crash since your if statement does not cover all situations

    if typeID == "P" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.prefix(trimLength)
        turnStringToIngeger = Int(trimmedString) ?? 0
    }
    else if typeID == "S" {
        var turnIntegerToString = String(integer)
        var trimmedString = turnIntegerToString.suffix(trimLength)
        turnStringToIngeger = Int(trimmedString) ?? 0
    }
    return turnStringToInteger
}

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