Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ライブラリでしかお目にかかれない珍しい実装

mikan
November 10, 2024

 ライブラリでしかお目にかかれない珍しい実装

mikan

November 10, 2024
Tweet

More Decks by mikan

Other Decks in Technology

Transcript

  1. 自己紹介 object Mikan { val name = "一瀬喜弘" val company

    = "karabiner.tech" val work = Engineer.Android val hobby = listOf( "漫画", "アニメ", "ゲーム", "折り紙", "OSS開発・コントリビュート", ) }
  2. @Immutable class ButtonColors constructor( val containerColor: Color, val contentColor: Color,

    val disabledContainerColor: Color, val disabledContentColor: Color, ) { fun copy( containerColor: Color = this.containerColor, contentColor: Color = this.contentColor, disabledContainerColor: Color = this.disabledContainerColor, disabledContentColor: Color = this.disabledContentColor ) = ButtonColors( containerColor.takeOrElse { this.containerColor }, contentColor.takeOrElse { this.contentColor }, disabledContainerColor.takeOrElse { this.disabledContainerColor }, disabledContentColor.takeOrElse { this.disabledContentColor }, ) // ... override fun hashCode(): Int { var result = containerColor.hashCode() result = 31 * result + contentColor.hashCode() result = 31 * result + disabledContainerColor.hashCode() result = 31 * result + disabledContentColor.hashCode() return result
  3. Avoid using data class Why data class が生成する、 copy や

    componentN メソッドにABI互換性がないから プロパティを追加したら、コンストラクタとcopyメソッドの互換性が壊れる プロパティの順番を変えたら、conponentNの互換性が壊れる https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api How 自前で hashCode や copy を実装している
  4. Readonly implementation What MutableStateFlow を StateFlow に up cast するときに利用されている

    public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> = ReadonlyStateFlow(this, null)
  5. Readonly implementation What public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> = ReadonlyStateFlow(this,

    null) @OptIn(ExperimentalForInheritanceCoroutinesApi::class) private class ReadonlyStateFlow<T>( flow: StateFlow<T>, @Suppress("unused") private val job: Job? // keeps a strong reference to the job (if present) ) : StateFlow<T> by flow, CancellableFlow<T>, FusibleFlow<T> { override fun fuse(context: CoroutineContext, capacity: Int, onBufferOverflow: BufferOverflow) = fuseStateFlow(context, capacity, onBufferOverflow) }
  6. Readonly implementation Why MutableStateFlowにdown castできてしまう class MainViewModel: ViewModel() { private

    val _uiState = MutableStateFlow(MainUiState()) val uiState: StateFlow<MainUiState> = _uiState } (viewModel.uiState as MutableStateFlow<MainUiModel>).update { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // down cast to MutableStateFlow }
  7. Readonly implementation Why ClassCastException が発生して、クラッシュする より安全な実装になる class MainViewModel: ViewModel() {

    private val _uiState = MutableStateFlow(MainUiState()) val uiState = _uiState.asStateFlow() } (viewModel.uiState as MutableStateFlow<MainUiModel>).update { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // throw ClassCastException }