Почему не выводится значение поле класса в цикле for в kotlin?
Имеется 3 демонстративных класса, два класса с "продуктом", и один класс для "заказа"
data class Coffee(
val id:Int,
val name:String,
val price:Int
)
data class Dessert(
val id:Int,
val name:String,
val price:Int
)
data class Order(
val id:Int,
val orderItem:MutableList<Any>,
)
Потом я создаю экземпляры классов "продукта", и передаю их в класс "заказа"
val coffee=Coffee(1,"test_coffee",2)
val dessert=Dessert(1,"test_dessert",4)
val order=Order(3, mutableListOf(coffee, dessert))
После чего я хочу через цикл пройтись по orderItem заказа, и сложить цену всех продуктов которые там хранятся. Но даже при простой попытки вывести ценник возникает ошибка.
for(i in order.orderItem){
println(i.price)
}
Unresolved reference: price
При условии того что тип данных внутри цикла определяется правильно.
for(i in order.orderItem){
println(i::class.java.typeName)
}
FileKt$main$Coffee
FileKt$main$Dessert
Ответы (1 шт):
Ну потому что у orderItem тип указан MutableList<Any>, значит для kotlin у переменной i будет тип Any, для которого не задано поле price.
Проще всего задать для всех заказов общий родительский класс или интерфейс, в котором указать поля, которые гарантированно есть у всех заказов, указать этот класс или интерфейс для orderItem вместо Any.
Через интерфейс:
interface OrderItem {
val id: Int
val name: String
val price: Int
}
data class Coffee(
override val id: Int,
override val name: String,
override val price: Int
) : OrderItem
data class Dessert(
override val id: Int,
override val name: String,
override val price: Int
) : OrderItem
data class Order(
val id: Int,
val orderItem: MutableList<OrderItem>,
)
val coffee = Coffee(1, "test_coffee", 2)
val dessert = Dessert(1, "test_dessert", 4)
val order = Order(3, mutableListOf(coffee, dessert))
for (i in order.orderItem) {
println("${i.name}: ${i.price}")
}
Или класс:
abstract class OrderItem(
open val id: Int,
open val name: String,
open val price: Int
)
data class Coffee(
override val id: Int,
override val name: String,
override val price: Int
) : OrderItem(id, name, price)
data class Dessert(
override val id: Int,
override val name: String,
override val price: Int
) : OrderItem(id, name, price)
data class Order(
val id: Int,
val orderItem: MutableList<OrderItem>,
)
val coffee = Coffee(1, "test_coffee", 2)
val dessert = Dessert(1, "test_dessert", 4)
val order = Order(3, mutableListOf(coffee, dessert))
for (i in order.orderItem) {
println("${i.name}: ${i.price}")
}
Вывод:
test_coffee: 2
test_dessert: 4
Еще вариант - явно проверять, что объект принадлежит конкретному классу, но это не удобно, если классов много, и не имеет особого смысла, если классы сильно пересекаются (много общих полей - в этом случае проще отнаследоваться от общего класса/реализовать общий интерфейс). Даже в данном случае с всего двумя классами появляется дублирующийся код:
for (i in order.orderItem) {
if (i is Coffee) {
println("${i.name}: ${i.price}")
} else if (i is Dessert) {
println("${i.name}: ${i.price}")
}
// или
when (i) {
is Coffee -> println("${i.name}: ${i.price}")
is Dessert -> println("${i.name}: ${i.price}")
}
}