将Swift的readline调用到同一个变量两次会忽略第二次调用

时间:2016-07-17 11:24:23

标签: swift null variable-assignment readline

我从命令行读取用户输入,检查它是否是有效的文件路径,并且 - 如果它没有要求用户重试。

如果用户输入为nil,则应首次将其视为任何其他错误输入,让用户输入新值,但第二次输入nil时,程序应该强制退出。

(我假设nil值是用户不会故意进入的,所以如果它发生了两次以上,我会假设出错了并退出程序以避免永无止境的循环要求新的输入。这可能是也可能不是一个好方法,但这不会影响问题。)

问题是readLine()如果收到了行结束输入(产生nil值),则第二次调用后不会要求用户输入。 (可以用^ D输入行尾。)

这意味着readLine()所在的函数会自动返回nil,因为这是接收readLine()的变量的最新值。

问题

  1. 无论接收变量已有多少值,都不应该readLine()被调用?

  2. 如果是这样,为什么用户在输入nil一次后才要求输入?

  3. 这是代码:

    import Foundation
    
    /**
        Ask the user to provide a word list file, check if the file exists. If it doesn't exist, ask the user again.
     */
    func askUserForWordList() -> String? {
        print("")
        print("Please drag a word list file here (or enter its path manually), to use as basis for the statistics:")
    
        var path = readLine(stripNewline: true) // THIS IS SKIPPED IF "PATH" IS ALREADY "NIL".
    
        return path
    }
    
    /**
        Check the user input // PROBABLY NOT RELEVANT FOR THIS QUESTION
     */
    func fileExists(filePath: String) -> Bool {
        let fileManager = NSFileManager.defaultManager()
    
        if fileManager.fileExistsAtPath(filePath) {
            return true
        } else {
            return false
        }
    }
    
    /**
        Get the file from the user and make sure it’s valid.
     */
    func getFilePathFromUser() throws -> String {
    
        enum inputError: ErrorType {
            case TwoConsecutiveEndOfFiles
        }
        var correctFile = false
        var path: String? = ""
        var numberOfConsecutiveNilFiles = 0
    
        repeat {
            // Check that the user did not enter a nil-value (end-of-file) – if they did so two times in a row, terminate the program as this might be some kind of error (so that we don't get an infinite loop).
            if numberOfConsecutiveNilFiles > 1 { // FIXME: entering ^D once is enough to end the program (it should require two ^D). Actually the problem seems to be in function "askUserForWordList()".
                throw inputError.TwoConsecutiveEndOfFiles
            }
    
            path = askUserForWordList()
    
            if path == nil {
                numberOfConsecutiveNilFiles += 1
            } else {
                numberOfConsecutiveNilFiles = 0
    
                correctFile = fileExists(path!)
    
                if !correctFile {
                    print("")
                    print("Oops, I couldn't recognize that file path. Please try again.")
                }
            }
        } while !correctFile
    
        return path!
    }
    
    // This is where the actual execution starts
    
    print("")
    print("=== Welcome to \"Word Statistics\", command line version ===")
    print("")
    print("This program will give you some statistics for the list of words you provide.")
    do {
        let path = try getFilePathFromUser()
    } catch {
        print("Error: \(error)")
        exit(-46) // Using closest error type from http://www.swiftview.com/tech/exitcodes.htm (which may not be standard at all. I could, however, not find any "standard" list of exit values).
    }
    

    备注

    • 当输入任何其他无效路径(任何字符串,甚至是空字符串(只需按Enter键)时,循环按预期工作。
    • path函数中的原始askUserForWordList()被声明为常量(let path = readLine(stripNewline: true)),但我将其更改为var,因为它应该在每次函数更新时更新调用。但是,这并不影响该计划的运作方式。
    • 我在调用path之前尝试单独声明readLine(),这没有任何区别。
    • 我尝试完全跳过path变量,让askUserForWordList()函数直接返回readLine()结果(return readLine(stripNewline: true))。这没什么区别。
    • 我一起跳过了askUserForWordList()函数,并将要求用户输入的代码移动到函数" getFilePathFromUser()"的“主要”代码中,但是没有'改变任何事情。

      修改后的代码:

      func getFilePathFromUser() throws -> String {
      
          enum inputError: ErrorType {
              case TwoConsecutiveEndOfFiles
          }
          var correctFile = false
          var path: String? = ""
          var numberOfConsecutiveNilFiles = 0
      
          repeat {
              // Check that the user did not enter a nil-value (end-of-file) – if they did so two times in a row, terminate the program as this might be some kind of error (so that we don't get an infinite loop).
              if numberOfConsecutiveNilFiles > 1 { // FIXME: entering ^D once is enough to end the program (it should require two ^D). Actually the problem seems to be in function "askUserForWordList()".
                  throw inputError.TwoConsecutiveEndOfFiles
              }
      
              // MODIFIED – This code was previously located in "askUserForWordList()"
              print("")
              print("Please drag a word list file here (or enter its path manually), to use as basis for the statistics:")
      
              path = readLine(stripNewline: true)
      
              // END OF MODIFICATION
      
              if path == nil {
                  numberOfConsecutiveNilFiles += 1
              } else {
                  numberOfConsecutiveNilFiles = 0
      
                  correctFile = fileExists(path!)
      
                  if !correctFile {
                      print("")
                      print("Oops, I couldn't recognize that file path. Please try again.")
                  }
              }
          } while !correctFile
      
          return path!
      }
      

1 个答案:

答案 0 :(得分:1)

如果(且仅当)标准输入文件描述符已到达文件结尾,

readLine()将返回nil。在读取输入时会发生这种情况(例如) 从tty开始,Ctrl-D"end-of-transmission character")作为第一个字符输入。

所有后续readLine()次调用都会返回nil,但没有 方式检测" Ctrl-D输入两次"。 换句话说,一旦标准输入处于文件结束条件 你不能再读取它的任何数据了。如果您的程序需要 如果您有更多数据,则只能报告错误,例如

guard let path = readLine(stripNewline: true) else {
    throw InputError.UnexpectedEndOfFile
}