Как напечатать несколько атрибутов из hashMap, который является свойством внутри переопределения toString - PullRequest
0 голосов
/ 29 октября 2019

Я изучаю Kotlin и пишу код для проверки моего понимания. Я пытаюсь использовать переопределение toString для печати значений hashMap, который является свойством класса. Я не могу заставить его работать. Вместо этого я получаю вывод типа "kotlin.Unit () -> kotlin.Unit". Кроме того, я не понимаю, почему значения hashMap печатаются перед выводом toString. Я не знаю, откуда этот вывод. Пожалуйста, помогите мне. Благодарю. Ниже мой код и вывод, который я получаю. Код:

package ch07.ExpandoObject

import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupport
import kotlin.properties.Delegates
import kotlin.reflect.KProperty


class Person(

    val name: String = "",
    age: Int? = null,
    var isMarried: Boolean? = null  ,_attributes: kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
)
    :PropertyChangeAware()
{
    var _attributes : kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
    fun setAttribute(attrName: String, value: String) {
        _attributes!!.set(attrName, value)
        _attributes!!.set("name", this.name)
    }


    override fun toString() = "Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) " +
            "${_attributes?.get("name")} " + "$name " +
            this._attributes!!.forEach { (attrName, value) -> println("$attrName = $value") } +
            {
                for ((attrName, value) in this._attributes!!) {
                    println("attribute $attrName = ${this._attributes!![attrName]}")
                }

            }

    val _age = ObservableProperty(propName = "age", propValue = age, changeSupport = changeSupport)

    private val observer = {
            prop: KProperty<*>, oldValue: Int, newValue: Int ->
        changeSupport.firePropertyChange(prop.name, oldValue, newValue)
    }

    var age: Int by Delegates.observable(initialValue = age?:99999,onChange = observer)



}

class ObservableProperty(val propName: String,
                         var propValue: Int?, val changeSupport: PropertyChangeSupport
) {
    fun getValue(): Int? = propValue

    fun setValue( newValue: Int) {
        val oldValue = propValue
        propValue = newValue
        changeSupport.firePropertyChange(propName, oldValue, newValue)
    }
}

open class PropertyChangeAware {
    val changeSupport = PropertyChangeSupport(this)

    fun addPropertyChangeListener(listener: PropertyChangeListener) {
        changeSupport.addPropertyChangeListener(listener)
    }

    fun removePropertyChangeListener(listener: PropertyChangeListener) {
        changeSupport.removePropertyChangeListener(listener)
    }
}


fun main(args: Array<String>) {
    val p = Person("Bob", 89, isMarried = false)
    val data = mapOf("lastname" to "Jones", "company" to "JetBrains")
    for ((attrName, value) in data)
        p.setAttribute(attrName, value)
    println(p)

}

Вот текущий вывод:

name = Bob
company = JetBrains
lastname = Jones
Person(name="Bob", age=89, isMarried=false) Bob Bob kotlin.Unit() -> kotlin.Unit

Еще раз спасибо за любую помощь.

1 Ответ

0 голосов
/ 29 октября 2019

Вы не должны использовать функции print() или println() внутри toString(), поскольку они выводят свои аргументы в стандартный вывод немедленно вместо добавления их в строку, возвращаемую вызывающей стороне.

Давайте рассмотрим вывод kotlin.Unit() -> kotlin.Unit, который вы получаете. Он состоит из двух частей:

  • kotlin.Unit - строковое представление выражения attributes!!.forEach { ... }. Функция forEach возвращает значение без значения, а в котлине это выражается путем возврата значения объекта Unit. Его строковое представление добавляется к возвращаемой строке.
  • вторая часть, () -> kotlin.Unit, также является строковым представлением лямбда-функции выражение { for((attrName, value) in ...) }. Эта функция не принимает параметров и возвращает без значения, что означает, что ее тип () -> Unit. Обратите внимание, что в Kotlin блок { ... } объявляет локальную лямбда-функцию. Если вместо этого вы хотите запустить код внутри этого блока, используйте функцию run: run { ... }

Цель функции toString состоит в том, чтобы построить представление строки объекта. И для этого вы можете использовать функцию buildString:

  override fun toString() = buildString {
    append("Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) ")
    append("${_attributes?.get("name")} ").append("$name ")
    this._attributes!!.forEach { (attrName, value) -> append("$attrName = $value") }
    for ((attrName, value) in this._attributes!!) {
      append("attribute $attrName = ${this._attributes!![attrName]}")
    }
  }

Эта функция создает StringBuilder и передает его как получатель своему функциональному аргументу ,где вы звоните append или appendln на этом приемнике. Затем buildString преобразует этот построитель строк в строку и возвращает ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...