我究竟如何解决这个“解缠”错误?

时间:2017-01-28 16:44:16

标签: swift optional

我正在学习编码,我正在尝试制作POS终端类型代码:

var stockCount = ["Pepsi": 450, "Sprite": 300, "Oreo Dairy MIlk": 3]
enum stockError : Error {
    case NotEnough
}

func cart(item: String, quantity: Int) throws -> Int {
    for (item, stock) in stockCount{
        guard quantity > stockCount[item] else {
            throw stockError.NotEnough
        }
    }   
}

为此,我收到以下错误:

ERROR at line 32, col 30: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
                guard quantity > stockCount[item] else {
                                           ^
                                                 !

请帮助!!

3 个答案:

答案 0 :(得分:1)

stockCount是一个词典。当您通过密钥访问字典的值时,密钥可能不存在,因此结果值是可选的。

换句话说,stockCount[item]返回一个可选值。您不能将<运算符(或其他运算符)与可选值一起使用。

有一些解决方案,但最直接的,因为您使用for循环并直接获取每个键和值,是将该行更改为:

guard quantity > stock else {

stockstockCount[item]的当前值,但它不会是可选的,因为for循环只提供字典中的实际现有值。

答案 1 :(得分:1)

有多种方法可以做到这一点。

解决方案1(在您的情况下推荐):直接与stock

进行比较
guard quantity > stock else {
    throw stockError.NotEnough
}

解决方案2:在进行比较之前手动检查nil

guard stockCountItem = stockCount[item], quantity > stockCountItem else {
    throw stockError.NotEnough
}

解决方案3:提供后备值以始终进行比较

guard quantity > (stockCount[item] ?? 0) else {
    throw stockError.NotEnough
}

答案 2 :(得分:0)

修复技术错误很容易。在其他答案中显示。但我不知道你的功能目标是什么。函数的名称没有任何线索。

逻辑错误

如果您检查库存是否足够,那么这是错误的:

guard quantity > stock else {
    throw stockError.NotEnough
}

它应该是当你想要更多然后库存抛出错误

guard quantity < stock else {
    throw stockError.NotEnough
}

当前代码

好吧让我们分析:

您有一个参数itemquantity,并且您希望Int作为返回类型。返回类型应该是什么?

var stockCount = ["Pepsi": 450, "Sprite": 300, "Oreo Dairy MIlk": 3]

enum StockError : Error {
    case NotEnough
}

func cart(item: String, quantity: Int) throws -> Int {
    print("Parameters item: \(item), quantity: \(quantity)")
    for (item, stock) in stockCount{
        print("compare for \(item): \(quantity) > \(stock)")
        guard quantity > stock else {
            throw StockError.NotEnough
        }
    }
    return 0
}

do {
    let result = try cart(item: "Pepsi", quantity: 200)
    print("Result: \(result)")

} catch let error as StockError  {
    print(error)
}

有了这个结果

Parameters item: Pepsi, quantity: 500
compare for Sprite: 500 > 300
compare for Pepsi: 500 > 450
compare for Oreo Dairy MIlk: 500 > 3
Result: 0

Parameters item: Pepsi, quantity: 450
compare for Sprite: 450 > 300
compare for Pepsi: 450 > 450
Error: NotEnough

Parameters item: Pepsi, quantity: 400
compare for Sprite: 400 > 300
compare for Pepsi: 400 > 450
Error: NotEnough

这个结果毫无意义。

重构

我会写这样的函数:

enum StockError : Error {
    case ItemNotExist(item: String)
    case NotEnough(item: String,currentCount: Int, missingCount: Int)
}

// Check Item if available and return remainig quantity
func checkItem(item: String, quantity: Int) throws -> Int {
    guard let stockItemCount = stockCount[item] else {
        throw StockError.ItemNotExist(item: item)
    }
    let remaining = stockItemCount - quantity
    guard remaining >= 0 else {
        throw StockError.NotEnough(item: item,currentCount: stockItemCount, missingCount: remaining)
    }
    return remaining
}

我的完整游乐场有记录和一些样本

我有一些时间,我玩了一点你的想法,这是我的游乐场

我用过:

  • 我可以设置LogLevel
  • 的记录器
  • 使用非常详细的日志记录 - 不需要生产代码
  • checkItems检查项目
  • checkCart查看购物车
  • sampleCarts针对某些示例购物车运行该功能以查看结果

根据需要设置LogLevel:

let logger = Logger(.verbose)

这是我的Playgound - 快乐的计划:)

var stockCount = ["Pepsi": 450, "Sprite": 300, "Oreo Dairy Milk": 3]


class Logger {

    let currentLogLevel: LogLevel

    init(_ logLevel: LogLevel){
        self.currentLogLevel = logLevel
    }

    enum LogLevel: Int {
        case info = 1
        case verbose = 2
    }

    func log(_ object: Any, logLevel: LogLevel = .verbose){
        if logLevel.rawValue <= currentLogLevel.rawValue {
            print(object)
        } else {
            //nothing
        }
    }

    func info(_ object: Any){
        log(object, logLevel: .info)
    }
    func verbose(_ object: Any){
        log(object, logLevel: .verbose)
    }
}


// Set LogLevel for logger

//let logger = Logger(.info)
let logger = Logger(.verbose)

enum StockError : Error {
    case ItemNotExist(item: String)
    case NotEnough(item: String,currentCount: Int, missingCount: Int)
}

// Check Item if available and return remainig quantity
func checkItem(item: String, quantity: Int) throws -> Int {
    logger.verbose("    checkItem: Parameters: item: '\(item)', quantity: \(quantity)")

    guard let stockItemCount = stockCount[item] else {
        throw StockError.ItemNotExist(item: item)
    }
    logger.verbose("    checkItem: available items for '\(item)': \(stockItemCount)")

    let remaining = stockItemCount - quantity
    logger.verbose("    checkItem: remaining items for '\(item)': \(remaining)")
    guard remaining >= 0 else {
        throw StockError.NotEnough(item: item,currentCount: stockItemCount, missingCount: remaining)
    }

    logger.verbose("    checkItem: Result: Remaining: \(remaining)")
    return remaining
}

func cartCheck(cart: [String:Int]) throws -> [String:Int]{
    logger.verbose("cartCheck: Parameters: cart: \(cart)\n")
    var result: [String:Int] = [:]
    for cartItem in cart{
        logger.verbose("  cartCheck: check for cartItem: '\(cartItem.key)', quantity: \(cartItem.value)")
        let checkResult = try checkItem(item: cartItem.key, quantity: cartItem.value)
        logger.verbose("  cartCheck: for '\(cartItem.key)' remaining: \(checkResult)\n")

        result[cartItem.key] = checkResult
    }
    logger.verbose("cartCheck: Result: \(result)\n")
    return result
}


func itemSamples(){

    do {
        let result = try checkItem(item: "Pepsi", quantity: 1)
        logger.verbose("Result: \(result)")
    } catch let error  {
        logger.verbose("Error: \(error)")
    }
}

func cartSamples(){

    let sampleCarts = [
        [
            "description": "normal Cart",
            "cart": ["Pepsi":300, "Sprite":200]
        ],
        [
            "description": "normal Cart",
            "cart": ["Pepsi":100, "Oreo Dairy Milk":2]
        ],
        [
            "description": "normal Cart - empty Stock",
            "cart": ["Pepsi":450, "Sprite": 300, "Oreo Dairy Milk": 3]
        ],
        [
            "description": "Fanta is not available",
            "cart": ["Pepsi":100, "Fanta":100]
        ],
        [
            "description": "not enougth Sprite",
            "cart": ["Pepsi":100, "Sprite":500]
        ],
        [
            "description": "too much oreo",
            "cart": ["Oreo Dairy Milk":100, "Sprite":20]
        ]

    ]

    for sampleCart in sampleCarts{
        logger.info("\n\nsample for: \(sampleCart["description"]!)")
        logger.info(" for stock: \(stockCount)")
        logger.info(" with cart: \(sampleCart["cart"]!)")


        do {
            let result = try cartCheck( cart: sampleCart["cart"]! as! [String : Int])
            logger.info("    Result: \(result)")
        } catch let error  {
            logger.verbose("")
            logger.info("     Error: \(error)")
        }
    }
}


itemSamples()
cartSamples()

LogLevel .info的结果:

sample for: normal Cart
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 200, "Pepsi": 300]
    Result: ["Sprite": 100, "Pepsi": 150]


sample for: normal Cart
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Pepsi": 100, "Oreo Dairy Milk": 2]
    Result: ["Pepsi": 350, "Oreo Dairy Milk": 1]


sample for: normal Cart - empty Stock
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
    Result: ["Sprite": 0, "Pepsi": 0, "Oreo Dairy Milk": 0]


sample for: Fanta is not available
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Fanta": 100, "Pepsi": 100]
     Error: ItemNotExist("Fanta")


sample for: not enougth Sprite
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 500, "Pepsi": 100]
     Error: NotEnough("Sprite", 300, -200)


sample for: too much oreo
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 20, "Oreo Dairy Milk": 100]
     Error: NotEnough("Oreo Dairy Milk", 3, -97)

LogLevel .verbose的结果:

    checkItem: Parameters: item: 'Pepsi', quantity: 1
    checkItem: available items for 'Pepsi': 450
    checkItem: remaining items for 'Pepsi': 449
    checkItem: Result: Remaining: 449
Result: 449


sample for: normal Cart
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 200, "Pepsi": 300]
cartCheck: Parameters: cart: ["Sprite": 200, "Pepsi": 300]

  cartCheck: check for cartItem: 'Sprite', quantity: 200
    checkItem: Parameters: item: 'Sprite', quantity: 200
    checkItem: available items for 'Sprite': 300
    checkItem: remaining items for 'Sprite': 100
    checkItem: Result: Remaining: 100
  cartCheck: for 'Sprite' remaining: 100

  cartCheck: check for cartItem: 'Pepsi', quantity: 300
    checkItem: Parameters: item: 'Pepsi', quantity: 300
    checkItem: available items for 'Pepsi': 450
    checkItem: remaining items for 'Pepsi': 150
    checkItem: Result: Remaining: 150
  cartCheck: for 'Pepsi' remaining: 150

cartCheck: Result: ["Sprite": 100, "Pepsi": 150]

    Result: ["Sprite": 100, "Pepsi": 150]


sample for: normal Cart
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Pepsi": 100, "Oreo Dairy Milk": 2]
cartCheck: Parameters: cart: ["Pepsi": 100, "Oreo Dairy Milk": 2]

  cartCheck: check for cartItem: 'Pepsi', quantity: 100
    checkItem: Parameters: item: 'Pepsi', quantity: 100
    checkItem: available items for 'Pepsi': 450
    checkItem: remaining items for 'Pepsi': 350
    checkItem: Result: Remaining: 350
  cartCheck: for 'Pepsi' remaining: 350

  cartCheck: check for cartItem: 'Oreo Dairy Milk', quantity: 2
    checkItem: Parameters: item: 'Oreo Dairy Milk', quantity: 2
    checkItem: available items for 'Oreo Dairy Milk': 3
    checkItem: remaining items for 'Oreo Dairy Milk': 1
    checkItem: Result: Remaining: 1
  cartCheck: for 'Oreo Dairy Milk' remaining: 1

cartCheck: Result: ["Pepsi": 350, "Oreo Dairy Milk": 1]

    Result: ["Pepsi": 350, "Oreo Dairy Milk": 1]


sample for: normal Cart - empty Stock
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
cartCheck: Parameters: cart: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]

  cartCheck: check for cartItem: 'Sprite', quantity: 300
    checkItem: Parameters: item: 'Sprite', quantity: 300
    checkItem: available items for 'Sprite': 300
    checkItem: remaining items for 'Sprite': 0
    checkItem: Result: Remaining: 0
  cartCheck: for 'Sprite' remaining: 0

  cartCheck: check for cartItem: 'Pepsi', quantity: 450
    checkItem: Parameters: item: 'Pepsi', quantity: 450
    checkItem: available items for 'Pepsi': 450
    checkItem: remaining items for 'Pepsi': 0
    checkItem: Result: Remaining: 0
  cartCheck: for 'Pepsi' remaining: 0

  cartCheck: check for cartItem: 'Oreo Dairy Milk', quantity: 3
    checkItem: Parameters: item: 'Oreo Dairy Milk', quantity: 3
    checkItem: available items for 'Oreo Dairy Milk': 3
    checkItem: remaining items for 'Oreo Dairy Milk': 0
    checkItem: Result: Remaining: 0
  cartCheck: for 'Oreo Dairy Milk' remaining: 0

cartCheck: Result: ["Sprite": 0, "Pepsi": 0, "Oreo Dairy Milk": 0]

    Result: ["Sprite": 0, "Pepsi": 0, "Oreo Dairy Milk": 0]


sample for: Fanta is not available
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Fanta": 100, "Pepsi": 100]
cartCheck: Parameters: cart: ["Fanta": 100, "Pepsi": 100]

  cartCheck: check for cartItem: 'Fanta', quantity: 100
    checkItem: Parameters: item: 'Fanta', quantity: 100

     Error: ItemNotExist("Fanta")


sample for: not enougth Sprite
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 500, "Pepsi": 100]
cartCheck: Parameters: cart: ["Sprite": 500, "Pepsi": 100]

  cartCheck: check for cartItem: 'Sprite', quantity: 500
    checkItem: Parameters: item: 'Sprite', quantity: 500
    checkItem: available items for 'Sprite': 300
    checkItem: remaining items for 'Sprite': -200

     Error: NotEnough("Sprite", 300, -200)


sample for: too much oreo
 for stock: ["Sprite": 300, "Pepsi": 450, "Oreo Dairy Milk": 3]
 with cart: ["Sprite": 20, "Oreo Dairy Milk": 100]
cartCheck: Parameters: cart: ["Sprite": 20, "Oreo Dairy Milk": 100]

  cartCheck: check for cartItem: 'Sprite', quantity: 20
    checkItem: Parameters: item: 'Sprite', quantity: 20
    checkItem: available items for 'Sprite': 300
    checkItem: remaining items for 'Sprite': 280
    checkItem: Result: Remaining: 280
  cartCheck: for 'Sprite' remaining: 280

  cartCheck: check for cartItem: 'Oreo Dairy Milk', quantity: 100
    checkItem: Parameters: item: 'Oreo Dairy Milk', quantity: 100
    checkItem: available items for 'Oreo Dairy Milk': 3
    checkItem: remaining items for 'Oreo Dairy Milk': -97

     Error: NotEnough("Oreo Dairy Milk", 3, -97)