← Назад к вопросам

Какие параметры получает оператор setValue у делегата

1.8 Middle🔥 221 комментариев
#Kotlin основы#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Краткий ответ

У делегата setValue получает три параметра:

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T)

Где:

  1. thisRef — объект-владелец свойства
  2. property — метаинформация о свойстве
  3. value — новое значение для установки

Детальное объяснение параметров setValue

1. thisRef: Any? — Ссылка на владельца свойства

Этот параметр содержит ссылку на объект, в котором объявлено свойство, использующее делегат.

Варианты:

  • null — если свойство объявлено на верхнем уровне (вне класса)
  • Экземпляр класса — если свойство является членом класса
  • Ссылка на companion object — для свойств в companion object

Пример использования:

class User {
    var name: String by Delegate()
}

class Delegate {
    private var storedValue: String = ""
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("Устанавливаем свойство '${property.name}' для объекта типа: ${thisRef?.javaClass?.simpleName}")
        storedValue = value
    }
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return storedValue
    }
}

val user = User()
user.name = "Алексей" // Выведет: Устанавливаем свойство 'name' для объекта типа: User

2. property: KProperty<*> — Метаинформация о свойстве

Через этот параметр можно получить информацию о самом свойстве:

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    println("Имя свойства: ${property.name}")
    println("Возвращаемый тип: ${property.returnType}")
    println("Аннотации: ${property.annotations.joinToString()}")
    println("Видимость: ${property.visibility}")
    
    // Логирование изменений
    println("Свойство '${property.name}' изменено на: $value")
}

Доступные свойства KProperty:

  • name — имя свойства
  • returnType — тип возвращаемого значения
  • annotations — список аннотаций
  • visibility — видимость свойства
  • isConst — является ли свойство константой

3. value: T — Новое значение

Типизированный параметр, содержащий значение, которое нужно присвоить свойству. Тип T должен соответствовать типу свойства.

class ValidatedDelegate {
    private var internalValue: String = ""
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        // Валидация перед установкой
        require(value.isNotBlank()) { 
            "Свойство '${property.name}' не может быть пустым" 
        }
        
        if (internalValue != value) {
            println("Значение '${property.name}' изменено: '$internalValue' -> '$value'")
            internalValue = value
        }
    }
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return internalValue
    }
}

Практический пример с наблюдаемым свойством

import kotlin.reflect.KProperty
import kotlin.properties.Delegates

class ObservableDelegate<T>(
    initialValue: T,
    private val onChange: (oldValue: T, newValue: T) -> Unit
) {
    private var value: T = initialValue
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
        val oldValue = value
        if (oldValue != newValue) {
            value = newValue
            onChange(oldValue, newValue)
            
            // Используем информацию из property для логирования
            println("""
                Свойство: ${property.name}
                Класс: ${thisRef?.javaClass?.simpleName ?: "Top-level"}
                Старое значение: $oldValue
                Новое значение: $newValue
            """.trimIndent())
        }
    }
}

// Использование
class Product {
    var price: Int by ObservableDelegate(100) { old, new ->
        println("Цена изменилась с $old на $new")
    }
}

fun main() {
    val product = Product()
    product.price = 150  // Вызовется setValue с thisRef=product, property=price, value=150
    product.price = 200  // Снова вызовется setValue
}

Важные особенности

Модификатор operator

Метод setValue должен быть объявлен с модификатором operator, иначе Kotlin не распознает его как оператор делегирования.

Типизация параметров

Тип параметра value должен строго соответствовать типу делегируемого свойства. Kotlin автоматически проверяет это на этапе компиляции.

Взаимодействие с getValue

setValue обычно используется в паре с getValue для создания полноценного делегата свойств с возможностью чтения и записи.

Область применения

  • ReadWriteProperty — интерфейс, объединяющий getValue и setValue
  • Ленивая инициализация (lazy)
  • Наблюдаемые свойства (Delegates.observable)
  • Привязка к View в Android (Binding)
// Пример с ReadWriteProperty
class CustomDelegate<T> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException("Value not initialized")
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

Понимание этих трех параметров критически важно для создания кастомных делегатов, которые являются мощным инструментом в Kotlin для реализации таких паттернов как наблюдатель (Observer), ленивая инициализация (Lazy) и привязка данных (Data Binding).

Какие параметры получает оператор setValue у делегата | PrepBro