Kotlin 데이터 클래스 용 getter 재정의
다음 Kotlin 클래스가 주어지면 :
data class Test(val value: Int)
Int
값이 음수이면 0을 반환하도록 getter를 어떻게 재정의 합니까?
이것이 가능하지 않은 경우 적절한 결과를 얻기위한 몇 가지 기술은 무엇입니까?
매일 Kotlin을 작성하는 데 거의 1 년을 보낸 후 이와 같은 데이터 클래스를 재정의하려는 시도가 나쁜 습관이라는 것을 알게되었습니다. 이에 대한 세 가지 유효한 접근 방식이 있으며, 제시 한 후에 다른 답변이 제안한 접근 방식이 왜 나쁜지 설명하겠습니다.
data class
잘못된 값으로 생성자를 호출하기 전에 값을 0 이상으로 변경하는 비즈니스 논리를 만드십시오 . 이것은 아마도 대부분의 경우에 가장 좋은 방법입니다.를 사용하지 마십시오
data class
. 일반을 사용하고class
IDE에서equals
및hashCode
메서드를 생성하도록 합니다 (또는 필요하지 않은 경우 에는 생성 하지 않음). 예, 개체의 속성이 변경된 경우 다시 생성해야하지만 개체를 완전히 제어 할 수 있습니다.class Test(value: Int) { val value: Int = value get() = if (field < 0) 0 else field override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Test) return false return true } override fun hashCode(): Int { return javaClass.hashCode() } }
효과적으로 재정의되는 개인 값을 갖는 대신 원하는 작업을 수행하는 추가 안전 속성을 개체에 만듭니다.
data class Test(val value: Int) { val safeValue: Int get() = if (value < 0) 0 else value }
다른 답변이 제안하는 잘못된 접근 방식 :
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
이 접근 방식의 문제점은 데이터 클래스 가 실제로 이와 같은 데이터를 변경하기위한 것이 아니라는 것입니다. 그들은 실제로 데이터를 보관하기위한 것입니다. 이 같은 데이터 클래스의 게터을 재정의하는 것을 의미 Test(0)
하고 Test(-1)
것없는 equal
서로 다른 것 hashCode
들,하지만 당신이 전화했을 때 .value
, 그들은 같은 결과를 가질 것이다. 이것은 일관성이 없으며 이것이 당신에게 효과가있을 수 있지만 이것이 데이터 클래스라고 생각하는 팀의 다른 사람들은 당신이 그것을 어떻게 변경했는지 / 예상대로 작동하지 않게 만들 었는지 깨닫지 못한 채 실수로 그것을 오용 할 수 있습니다. t Map
또는 a Set
) 에서 올바르게 작동합니다 .
다음과 같이 시도해 볼 수 있습니다.
data class Test(private val _value: Int) {
val value = _value
get(): Int {
return if (field < 0) 0 else field
}
}
assert(1 == Test(1).value)
assert(0 == Test(0).value)
assert(0 == Test(-1).value)
assert(1 == Test(1)._value) // Fail because _value is private
assert(0 == Test(0)._value) // Fail because _value is private
assert(0 == Test(-1)._value) // Fail because _value is private
데이터 클래스에서 기본 생성자의 매개 변수를
val
또는 로 표시해야합니다var
.나는 값 할당하고 있습니다
_value
로를value
속성에 원하는 이름을 사용하기 위해.설명하신 논리로 속성에 대한 사용자 지정 접근자를 정의했습니다.
대답은 실제로 사용하는 기능에 따라 다릅니다 data
. @EPadron은 멋진 트릭 (개선 버전)을 언급했습니다.
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
그 의지는 예상대로 EI가있다, 작동 하나 개의 권리, 필드, 하나 게터를 equals
, hashcode
하고 component1
. 캐치는 저것 toString
이며 copy
이상합니다.
println(Test(1)) // prints: Test(_value=1)
Test(1).copy(_value = 5) // <- weird naming
문제를 해결하기 위해 toString
손으로 재정의 할 수 있습니다. 매개 변수 이름 지정을 수정하는 방법은 없지만 전혀 사용하지 않는 방법을 알고 있습니다 data
.
나는 이것이 오래된 질문이라는 것을 알고 있지만 아무도 가치를 비공개로 만들고 다음과 같이 사용자 정의 getter를 작성할 가능성을 언급하지 않은 것 같습니다.
data class Test(private val value: Int) {
fun getValue(): Int = if (value < 0) 0 else value
}
Kotlin은 비공개 필드에 대한 기본 getter를 생성하지 않으므로 완벽하게 유효해야합니다.
그러나 그렇지 않으면 데이터 클래스가 데이터를 보관하기위한 것이며 "비즈니스"논리를 하드 코딩하지 않아야한다는 spierce7에 확실히 동의합니다.
이것은 Kotlin의 성가신 단점 중 하나 인 것 같습니다.
클래스의 이전 버전과의 호환성을 완전히 유지하는 유일한 합리적인 솔루션은 클래스를 일반 클래스 ( "데이터"클래스가 아님)로 변환하고 IDE의 도움을 받아 수동으로 메서드를 구현하는 것 같습니다. hashCode ( ), equals (), toString (), copy () 및 componentN ()
class Data3(i: Int)
{
var i: Int = i
override fun equals(other: Any?): Boolean
{
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Data3
if (i != other.i) return false
return true
}
override fun hashCode(): Int
{
return i
}
override fun toString(): String
{
return "Data3(i=$i)"
}
fun component1():Int = i
fun copy(i: Int = this.i): Data3
{
return Data3(i)
}
}
I found the following to be the best approach to achieve what you need without breaking equals
and hashCode
:
data class TestData(private var _value: Int) {
init {
_value = if (_value < 0) 0 else _value
}
val value: Int
get() = _value
}
// Test value
assert(1 == TestData(1).value)
assert(0 == TestData(-1).value)
assert(0 == TestData(0).value)
// Test copy()
assert(0 == TestData(-1).copy().value)
assert(0 == TestData(1).copy(-1).value)
assert(1 == TestData(-1).copy(1).value)
// Test toString()
assert("TestData(_value=1)" == TestData(1).toString())
assert("TestData(_value=0)" == TestData(-1).toString())
assert("TestData(_value=0)" == TestData(0).toString())
assert(TestData(0).toString() == TestData(-1).toString())
// Test equals
assert(TestData(0) == TestData(-1))
assert(TestData(0) == TestData(-1).copy())
assert(TestData(0) == TestData(1).copy(-1))
assert(TestData(1) == TestData(-1).copy(1))
// Test hashCode()
assert(TestData(0).hashCode() == TestData(-1).hashCode())
assert(TestData(1).hashCode() != TestData(-1).hashCode())
However,
First, note that _value
is var
, not val
, but on the other hand, since it's private and data classes cannot be inherited from, it's fairly easy to make sure that it is not modified within the class.
Second, toString()
produces a slightly different result than it would if _value
was named value
, but it's consistent and TestData(0).toString() == TestData(-1).toString()
.
참고URL : https://stackoverflow.com/questions/38492103/override-getter-for-kotlin-data-class
'Programing' 카테고리의 다른 글
Android INSTALL_FAILED_UID_CHANGED (0) | 2020.10.24 |
---|---|
“구성 파일 /etc/nginx/nginx.conf 테스트 실패”:이 문제가 발생한 이유를 어떻게 알 수 있습니까? (0) | 2020.10.24 |
입력 유형 = "파일"에서 커서 유형 변경 (0) | 2020.10.24 |
VBA에서 dim과 set의 차이점은 무엇입니까 (0) | 2020.10.24 |
개체가 매개 변수 유형의 인스턴스인지 테스트 (0) | 2020.10.24 |