2014-11-11 4 views
3

내가 코 틀린를 공부하고 학습의 일환으로 나는 유리수, 요구 사항을 나타낼 것이다 클래스 설계 할 :Kotlin 개체를 초기화하는 동안 임시 변수를 저장하는 방법은 무엇입니까?

  • 클래스는 두 개의 불변의 정수 필드를 포함해야합니다 : 분자와 분모를.
  • 클래스에는 유효한 equals, hashCode 및 toString 구현이 포함되어야합니다. 클래스가 초기화되면
  • , 분자와 분모가 GCD 삭제되어야한다
  • 이 클래스는 다른 비율을 얻어 현재 비율과 주어진 하나의 승산 결과를 반환 MUL 방법을 포함한다 (이는 Ratio(1, 2) == Ratio(2, 4 /* or 4, 8 */) or Ratio(2, 4 /* or 4, 8 */).numerator == 1, .denominator == 2 등을 의미) .

데이터 클래스를 사용하여 해당 작업에 적합한 것으로 보았습니다. 그러나 사용자 지정 생성자를 정의하지 못했습니다 (분자와 분모를 GCD로 삭제해야 함).

가능한 해결 방법 :

class Ratio(num : Int, denom : Int) { 
    val numerator = num/gcd(num, denom) 
    val denominator = denom/gcd(num, denom) // GCD calculated twice! 
} 

GCD 한 번 계산되도록 클래스 생성자를 정의하는 가장 간단한 방법은 무엇입니까? 나는 가능한 솔루션을 찾을처럼

OK UPDATE, 그것은 보지 않는다 :

data class Ratio(num : Int, denom : Int) { 
    val numerator : Int 
    val denominator : Int 

    { 
    val gcd = calcGcd(num, denom) 
    numerator = num/gcd 
    denominator = denom/gcd 
    } 
} 

을하지만 데이터가 쓸모 한정자 것을 렌더링 -이 변경 비율 클래스가 더 이상 자동 등호를 생성 한 후/해시 코드/toString.

코 틀린의 최신 버전에 검증 - 그 동작을 재현 0.9.66

프로그램 :

data class Ratio(num : Int, denom : Int) { 
    val numerator : Int 
    val denominator : Int 

    { 
    val gcd = BigInteger.valueOf(num.toLong()).gcd(BigInteger.valueOf(denom.toLong())).intValue(); 
    numerator = num/gcd; 
    denominator = denom/gcd 
    } 
} 

data class Ratio2(val num : Int, val denom : Int) 

fun main(args: Array<String>) { 
    println("r = " + Ratio(1, 6).toString()) 
    println("r2 = " + Ratio2(1, 6).toString()) 
} 

출력 :

r = [email protected] 
r2 = Ratio2(num=1, denom=6) 

비율이 더 이상 자동으로 생성 한 것이 분명 없다 toString 메서드

+0

당신은 쓸데없는'데이터 '문제를 JetBrains에보고 했습니까? 버그처럼 들린다 –

답변

3

OK, 내가 대답을 볼 수있는 기술 사용의 경우 개인의 ctor를 가질 필요성을 지적 안드레이에 (감사) :

어떤 이유로
data class Ratio private (val numerator : Int, val denominator : Int) { 
    class object { 
    fun create(numerator : Int, denominator : Int) : Ratio { 
     val gcd = BigInteger.valueOf(numerator.toLong()).gcd(BigInteger.valueOf(denominator.toLong())).intValue(); 
     return Ratio(numerator/gcd, denominator/gcd) 
    } 
    } 
} 

초기화 블록 클래스에서 사용하는 경우 '데이터'규정은 무용지물이 될 것이다, 그래서 당신은 사용자 정의 건설 논리를 가지고 자동차를 유지하려면 '해시 코드//의 toString 방법 당신에게 동일 생성 팩토리 메소드를 사용해야합니다. .

+1

이 개념을 약간 개선했습니다. http://kotlin-demo.jetbrains.com/?publicLink=1040749715610173087711795561819 –

+0

고마워요! 사용자 정의 ctor 논리를 원한다면 invoke를 사용할 수 있다는 사실을 놓쳤습니다. – Alex

+0

또한'copy'를 정의해야합니다. 그렇지 않으면 불변성을 깨는 방법이있을 것입니다 –

0

어웨이 정도 :

class Ratio(num : Int, denom : Int) { 
private val theGcd = gcd(num, denom) 
val numerator = num/theGcd 
val denominator = denom/theGcd 
} 

EDIT : 공정한 쓸데없는 필드에 대해. 대안으로는 느린 평가 속성을 사용할 수 있습니다. 이에 가서 여기 (안된를)입니다 여기에 문서 http://kotlinlang.org/docs/reference/delegated-properties.html

참조하십시오 ..

import kotlin.properties.Delegates 

class Ratio(num : Int, denom : Int) { 
private val theGcd: Int by Delegates.lazy { 
    gcd(num, denom) 
} 

val numerator = num/theGcd 
val denominator = denom/theGcd 
} 
+0

아니요, 클래스 인스턴스에 중복 값을 영구적으로 추가하는 나쁜 것입니다. 장난감 샘플에서는 괜찮을 지 모르지만 클래스 레이아웃이 커지면 인스턴스에 실제로 필요한 것보다 훨씬 많은 메모리를 소비하게됩니다. 클래스 비율 (NUM : INT, denom : INT) { 발 분자 : 지능 발 분모 :이 가진 유일한 문제는 추가 필드 인 경우는 쉽게 – Alex

+1

을 제거하는 지능 { 발 theGcd = GCD (NUM, denom) 분자 = NUM ​​/ theGcd 분모 = denom/theGcd } } (https://gist.github.com/abreslav/173c32a30f9f94e1cd9a) 당신이 원하는 것은 경우 자동으로 생성 된' equals' /'hashCode' 등, 개인 생성자와 팩토리 메소드가 필요합니다 –

+0

감사합니다 Andrey. 제발, 위의 내 편집을 참조하십시오 - 나는 '데이터'한정자를 사용하고자하고 이니셜 라이저 블록에서 임시 변수를 제거한 후에 '데이터'한정자가 쓸모없는 것으로 나타났습니다. – Alex