【问题标题】:Variable used before being initialized in function在函数中初始化之前使用的变量
【发布时间】:2016-06-23 07:15:42
【问题描述】:

我正在制作ro sham bo 游戏。 swift 中的函数与我之前使用的不同。我不断收到错误消息:

在函数中初始化之前使用的变量

我做错了什么?

import Foundation
import UIKit
class Result: UIViewController {
    var rval: Int?
    var chosen: Int?
    func determineWinner() -> Int {
        var returnval: Int
        if (chosen == rval){
            returnval = 2
        }
        else if (chosen == 1 && rval == 3){
            returnval = 1
        }
        else if (chosen == 1 && rval == 2){
            returnval = 0
        }
        else if (chosen == 2 && rval == 1){
            returnval = 1
        }
        return (returnval)
    }

    @IBOutlet weak var wl: UILabel!

    @IBAction func PlayAgain(sender: AnyObject) {
    }
    override func viewDidLoad() {
        print(chosen)
    }
}

【问题讨论】:

  • 哪个变量?代码在哪里?
  • 如果没有一个 if 语句匹配,则 returnval 没有值,这就是错误的原因。
  • 如果函数中没有任何 if-else 语句触发怎么办?在这种情况下,您希望它返回什么?您需要为returnval 提供某种形式的默认值,或者让您的函数返回一个可选值。
  • 改进的代码格式;澄清措辞并提供游戏链接。
  • 如果回答了您的问题,请记得投票并接受答案。

标签: ios swift


【解决方案1】:

Swift 程序流程中的每个可能路径都必须有一个已定义的返回值。在您的情况下,如果 if/else if/else 部分都被跳过,则 returnval 未分配。因此,没有返回有效值。试试这个:

import Foundation
import UIKit //space things out to be easier to read

class Result: UIViewController {

    var rval: Int? //these should have better names
    var chosen: Int?

    func determineWinner() -> Int {

        var returnval = -1 //needs a default value

        if (chosen == rval){
            returnval = 2
        }
        else if (chosen == 1 && rval == 3){
            returnval = 1
        }
        else if (chosen == 1 && rval == 2){
            returnval = 0
        }
        else if (chosen == 2 && rval == 1){
            returnval = 1
        }

        return returnval //don't put return value in brackets
    }

    @IBOutlet weak var wl: UILabel!

    @IBAction func PlayAgain(sender: AnyObject) {
    }

    override func viewDidLoad() {
        print(chosen) 
    }
}

这也是使用switch 语句的模式匹配的一个很好的候选。这是我认为与Sean's suggestion.一起使用的方法

var determineWinner: Int? {

    guard let chosen = chosen, let rval = rval else {
        //handle error, either chosen or rval is nil
        return nil
    }

    switch ((chosen, rval)) {
    case let (x, y) where x == y: return 2
    case (1, 3): return 1
    case (1, 2): return 0
    case (2, 1): return 1

    default:
        print("handle default case here")
        return nil;
    }
}

【讨论】:

  • 您好,要在 switch 子句中使用可选项,您需要在案例中添加类似 case (Optional<Int>.Some(1), Optional<Int>.Some(3)): return 1 的内容。
  • 很好,我忘了他们是有条件的。我认为最好guard他们
  • 没问题,剩下的你的答案是完美的。
  • 你喜欢我的后卫想法,正如我所看到的:p
  • 复制了你答案的几个部分但是guard是我的想法:D
【解决方案2】:

有问题的语句是 return (returnval),因为 Swift 编译器认为有一个通过 if-then-else 链的通道不会导致分配 returnval

例如,如果chosen 为 3,rval 为 2,则不会有赋值。

也许你程序的其他部分使得chosen 不可能同时为 3 而rval 为 2,但 Swift 对此一无所知,因此它会报告错误。为了修复编译错误,给returnval添加一个初始值。

如果您绝对确定您的 if-then-else 链枚举了所有有效的可能性,请将 returnval 设置为 -1,并在返回之前断言它被设置为非负值:

var returnval = -1
... // your conditionals go here
assert(returnval >= 0, "Logic of determineWinner is broken")
return returnval

【讨论】:

    【解决方案3】:

    尝试var returnval: Int = 0(或另一个随机数,以防您的 if-else 语句详尽无遗)

    【讨论】:

      【解决方案4】:

      返回一个 Int?

      正如其他人已经说过的,问题是你的条件都不满足,然后returnval 没有被初始化。

      您可以使用 switch 语句 + 保护 + 计算属性。像这样

      var winner: Int? {
          guard let chosen = chosen, rval = rval else { return nil }
          switch (chosen, rval) {
          case (let chosen, let rval) where chosen == rval : return 2
          case (1, 3): return 1
          case (1, 2): return 0
          case (2, 1): return 1
          default: return nil
          }
      }
      

      请注意我稍微改变了你的逻辑。事实上,在我的代码中,如果选择和 rval 都为零,则返回值为零。在您的代码中返回 2。您应该更改它,也许在我的代码之上添加另一个 guard。类似的东西

      guard chosen != rval else { return 2 } 
      

      返回 Int + 致命错误

      如果您知道选择并且 rval 将始终被填充,那么

      var winner: Int {
          guard let chosen = chosen, rval = rval else { fatalError() }
          switch (chosen, rval) {
          case (let chosen, let rval) where chosen == rval : return 2
          case (1, 3): return 1
          case (1, 2): return 0
          case (2, 1): return 1
          default: fatalError()
          }
      } 
      

      【讨论】:

        【解决方案5】:

        已编辑

        问题解决

        您收到初始化程序错误,因为您在设置之前没有使用Int() 初始化returnval

        代码改进

        考虑使用计算属性来返回获胜者的值。我在下面的代码中做出了假设,您使用的值 2 根据您的逻辑推断出平局情况。

        在这里,我创建了一个枚举,以确保仅以您期望结果表示的这些特定方式处理返回的值。您仍然可以通过枚举案例上的哈希值访问 Int 值。使用.rawValue 这样做。

        在这种情况下尽量避免使用Int 值很重要,因为它们可以是其他值。

        在下面包含的代码中,我给您写了一组 guard 语句,当检查的值不允许确定获胜者状态时,它们会失败并返回 fatalError 消息。

        改进的代码

        import Foundation
        import UIKit
        
        
        class Result: UIViewController {
        
          var rval: Int?
          var chosen: Int?
        
          enum Winner: Int {
            case one  = 0
            case two  = 1
            case tie  = 2
          }
        
          var winner: Winner? {
        
            guard (rval > 0 || rval < 4) else {
              fatalError("rval out of bounds: cannot determine winner")
            }
            guard (chosen > 0 || chosen < 3) else {
              fatalError("chosen out of bound: cannot determine winner")
            }
            guard (rval != nil && chosen != nil) else {
              fatalError("rval or chosen are nil: cannot determine winner")
            }
        
            switch (chosen!, rval!) {
            case (let chosen, let rval) where chosen == rval: return Winner.tie
            case (1, 3): return Winner.two
            case (1, 2): return Winner.one
            case (2, 1): return Winner.two
        
            default:
              return nil
            }
          }
        
        
          @IBOutlet weak var wl: UILabel!
        
          @IBAction func PlayAgain(sender: AnyObject) {
          }
          override func viewDidLoad() {
            print(chosen)
          }
        }
        

        作为旁注,请务必为您喜欢的答案 +1!

        【讨论】:

        • 我要把我们的两个答案结合在一起
        • 同意,我喜欢你的 switch 语句
        • 我喜欢你对可选和计算属性的使用。我回了-1。我觉得很脏。
        【解决方案6】:

        你可以让这更迅速。

        例如... 为什么使用Int 来表示不同的动作?在这里,我使用了一个枚举来表示获胜的动作和背后的逻辑......

        enum RoShamBo {
            case Rock
            case Paper
            case Scissors
        
            func beats(opposingPlay: RoShamBo) -> Bool {
                return self > opposingPlay
            }
        }
        
        // I thought it made sense to make it Comparable.
        // That way you can use the < or > operator to determine
        // the winning move.
        // I then used this in the function beats() above
        extension RoShamBo: Comparable {}
        
        func < (lhs: RoShamBo, rhs: RoShamBo) -> Bool {
            // this is required for Comparable
            // in this we return true if lhs loses to rhs
        
            // Scissors beat Paper
            return lhs == .Paper && rhs == .Scissors
            // Paper beats Rock
                || lhs == .Rock && rhs == .Paper
            // Rock beats Scissors
                || lhs == .Scissors && rhs == .Rock
        }
        

        那么你需要做的就是用某种PlayerGame 类型的东西来包装它......

        struct Player {
            let name: String
            let move: RoShamBo
        }
        
        struct Game {
            func winner(player1: Player, player2: Player) -> Player? {
                if player1.move.beats(opposingPlay: player2.move) {
                    return player1
                }
        
                if player2.move.beats(opposingPlay: player1.move) {
                    return player2
                }
        
                // tie
                return nil
            }
        }
        
        let p1 = Player(name: "Oliver", move: .Rock)
        let p2 = Player(name: "Geoff", move: .Scissors)
        
        let game = Game()
        
        let winner = game.winner(player1: p1, player2: p2)
        
        print(winner)
        
        //Output Optional(Player(name: "Oliver", move: RoShamBo.Rock))
        

        整个过程中没有使用一个 Int,您可以准确地看到获胜的举动是什么以及谁赢了等等......

        枚举确实比它们在 Swift 中的功劳强大得多。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-23
          • 1970-01-01
          • 2015-07-04
          • 2021-09-13
          • 2015-11-10
          相关资源
          最近更新 更多