When식에서는 조건이 엇갈려도 속성이 Mutable이기 때문에 스마트카드를 주지 않습니다!시간의 대응법

21454 단어 Kotlintech
이 글은 Qrunch 서비스 종료와 함께 이전된 투고입니다.
Qita→QrunchQiita Edition의 자기 전재를 옮기기 위해서다.
이것은 최근에 코드가 생성한 어둠 속에서 마시는 필터다.
4자리 행 코드를 생성하고 2자리 숫자를 생성했습니다.
따라서 샘플 코드는 자동으로 생성된 악취 코드이므로 양해해 주십시오.

발생한 문제


다음 코드를 썼다고 가정해 보세요.쓰여 있거나.
class XxxBuilderScope {
    var duplicatedField: DuplicatedField? = null

    fun String.toDuplicatedField() = DuplicatedField.String(this)
    fun Int.toDuplicatedField() = DuplicatedField.Int(this)
    fun Regex.toDuplicatedField() = DuplicatedField.Regex(this)operator fun DuplicatedField?.div(value: Int) = DuplicatedField.Int(value)
    operator fun DuplicatedField?.div(value: String) = DuplicatedField.String(value)
    operator fun DuplicatedField?.div(value: Regex) = DuplicatedField.Regex(value)

    sealed class DuplicatedField {
        data class String(val value: kotlin.String) : DuplicatedField()
        data class Int(val value: kotlin.Int) : DuplicatedField()
        data class Regex(val value: kotlin.text.Regex) : DuplicatedField()
    }

    fun build() {
        val builder = Unit
        when(duplicatedField) {
            is DuplicatedField.String -> println(duplicatedField.value)
            is DuplicatedField.Int -> println(duplicatedField.value)
            is DuplicatedField.Regex -> println(duplicatedField.value)
        }
    }
}
이 코드는 컴파일할 수 없습니다.다음 오류가 발생했습니다.Error:(26, 50) Kotlin: Smart cast to 'XxxBuilderScope.DuplicatedField.String' is impossible, because 'duplicatedField' is a mutable property that could have been changed by this time네.표제 회수.
정음 속성은 기본적으로 다른 라인에서 다시 쓸 가능성이 있기 때문에 스마트 방송을 할 수 없다.
대단해!kotlinc는 라인의 안전을 고려하는 똑똑한 컴파일러입니다!

해결책


일반적인 처리 방법은 두 가지가 있다.수동으로 할당할지, val의 로컬 변수를 다시 대입할지.
여기에는 후자의 방법과 코틀린 1.3에 새로 추가된 문법을 사용해 우아하게 풀어낸다.
수정된 코드는 when 부분만 표시됩니다.
when(val v = duplicatedField) {
    is DuplicatedField.String -> println(v.value)
    is DuplicatedField.Int -> println(v.value)
    is DuplicatedField.Regex -> println(v.value)
}
응, 간단하지?(cv: 튀니지 펭귄)


샘플 코드를 생성하는 코드의 일부(Kotlinpoet)
또한build ()는 다른 곳에 있습니다
OSS입니다.justincase-jp/AWS-CDK-Kotlin-DSL(홍보)
private fun TypeSpec.Builder.addPropertyForDuplicatedMethods(name: String, methods: List<KFunction<*>>) {
        val decapitalName = name.decapitalize()
        val capitalName = name.capitalize()

        // sealed class DuplicatedField
        val sealedType = TypeSpec.classBuilder(capitalName)
            .addModifiers(KModifier.SEALED)

        // var duplicatedField: DuplicatedField? = null
        val sealedClassName = ClassName("", capitalName)
        val prop = PropertySpec.builder(decapitalName, sealedClassName.copy(nullable = true))
            .initializer("null")
            .mutable(true)
            .build()
        addProperty(prop)

        methods.forEach { func ->
            val parameterType = func.parameters.single { it.kind == KParameter.Kind.VALUE }.type.classifier as KClass<*>
            // data class String(val value: kotlin.String) : DuplicatedField()
            val constructor = FunSpec.constructorBuilder()
                .addParameter("value", parameterType)
                .build()
            val clazz = TypeSpec.classBuilder(parameterType.simpleName!!)
                .primaryConstructor(constructor)
                .addProperty(
                    PropertySpec.builder("value", parameterType)
                        .initializer("value")
                        .build()
                ).superclass(sealedClassName)
                .build()
            sealedType.addType(clazz)

            // fun String.toDuplicatedField() = DuplicatedField.String(this)
            val converterFunc = FunSpec.builder("to$capitalName")
                .receiver(parameterType)
                .returns(sealedClassName)
                .addStatement("return $capitalName.${parameterType.simpleName}(this)")
                .build()
            addFunction(converterFunc)

            // operator fun DuplicatedField?.div(value: Int) = DuplicatedField.Int(value)
            val operatorFunc = FunSpec.builder("div")
                .receiver(parameterType.asClassName().copy(nullable = true))
                .addParameter("value", parameterType)
                .returns(sealedClassName)
                .addStatement("return $capitalName.${parameterType.simpleName}(value)")
                .build()
            addFunction(operatorFunc)
        }

        addType(sealedType.build())
    }

좋은 웹페이지 즐겨찾기