-3

I have a struct "Person" which I want to reassign each individual object's amount from the structArray which I declared. When I do a for each loop to reassign the amount, an error says

Left side of mutating operator isn't mutable: 'person' is a 'let' constant

struct Person {

    let name : String
    var amount : Double
}

var structArray:[Person] = []

func calculateBill(pax: [Person]) -> [Person] {

    for person in pax {

        person.amount += taxByPerson //error
    }

    return pax
}

What is causing the issue and how can I fix this to be able to reassign the value?

EDIT: Thanks guys for pointing out where my error was, although the downvoting is pretty depressing to watch lol.

func calculateBill(pax: [Person]) -> [Person] {

    var finalBill:[Person] = pax        

    for i in 0..<finalBill.count {

        finalBill[i].amount += taxByPerson      
    }

    return finalBill
}
iamhx
  • 472
  • 6
  • 24
  • The function does not compile anyway – vadian Mar 20 '17 at 18:16
  • Why not? @vadian – iamhx Mar 20 '17 at 18:17
  • 1
    The parameter label `newPax` is not related to the function – vadian Mar 20 '17 at 18:18
  • Oh, sorry. Syntax problem. Edited – iamhx Mar 20 '17 at 18:19
  • 1
    You need to 1) create a mutable copy of the array inside the function and 2) create a mutable copy of the person inside the for loop and then assign it back to the array after mutating it. – dan Mar 20 '17 at 18:20
  • @iamhx Does it make sense for a person's name to be mutable? 0.o – Alexander Mar 20 '17 at 18:22
  • @Alexander You're right. Since theres no need to reassign the name – iamhx Mar 20 '17 at 18:24
  • 1
    Note that your updated code won't mutate the actual elements in the array because `person` in the loop is a mutable *copy* of the given array element at that iteration. One way to do what you want is to iterate over indices instead, see for example http://stackoverflow.com/q/26371751/2976878 – Hamish Mar 20 '17 at 18:38

2 Answers2

0

Well the error is exactly what it says on the tin... person is a let context. You'll need to use var. But this is more easily accomplished with map

struct Person {
    var name: String
    var amount: Double
}

var people = [Person]()

func calculateBill(_ people: [Person]) -> [Person] {
    return people.map{ 
        var p = $0
        p.amount += taxByPerson
        return p
    }
}
Alexander
  • 59,041
  • 12
  • 98
  • 151
  • That won't work because `$0` is immutable and `+=` returns `Void`. `return people.map { Person(name: $0.name, amount: $0.amount + taxByPerson) }` perhaps? :) – Hamish Mar 20 '17 at 18:29
  • @Hamish Fixed, although it does ruin some of the charm – Alexander Mar 20 '17 at 19:17
0

Value types could be a pain and passed parameters are constants (let) by definition.

You could pass the array as an inout parameter, in the function add the value directly in the array:

func calculateBill(pax: inout [Person]) {
    for index in 0..<pax.count {
        pax[index].amount += taxByPerson
    }
}

and call it

calculateBill(pax: &structArray)
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Or `for index in pax.indices {...}` – also you can totally get rid of the `var people = pax` & `pax = people` given you're just mutating `pax` anyway. – Hamish Mar 20 '17 at 18:51