You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Dagger Hilt向Kotlin扩展函数注入参数?

问题描述

我有一个将Int格式化为货币字符串的Kotlin扩展函数:

fun Int.asCurrency(formatter: NumberFormat): String {
    formatter.maximumFractionDigits = 0
    return formatter.format(this)
}

因为在RecyclerView中调用时不想每次创建新的NumberFormat实例,我会传入已有的实例,也试过用单例类复用:

object Formatter {
    val currencyFormatter: NumberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault())
}

fun Int.asCurrency(): String {
    Formatter.currencyFormatter.maximumFractionDigits = 0
    return Formatter.currencyFormatter.format(this)
}

现在我在学习依赖注入,想用Dagger Hilt给这个函数注入NumberFormat实例,尝试了以下实现:

@Module
@InstallIn(SingletonComponent::class)
object FormatterModule {
    @Singleton
    @Provides
    fun provideCurrencyFormatter(): NumberFormat {
        return NumberFormat.getCurrencyInstance(Locale.getDefault())
    }
}

@Inject
fun Int.asCurrency(formatter: NumberFormat): String {
    formatter.maximumFractionDigits = 0
    return formatter.format(this)
}

但这个方案没用,调用函数时还是得传参数。后来试了字段注入:

@Inject
fun Int.asCurrency(): String {
    lateinit var formatter: NumberFormat
    formatter.maximumFractionDigits = 0
    return formatter.format(this)
}

结果编译报错:error: Dagger does not support injection into static methods。

想问:如何向Kotlin扩展函数注入参数?或者至少怎么给普通Kotlin函数注入参数?


解决方案

1. 封装工具类间接实现注入

Kotlin扩展函数本质是静态方法,Dagger Hilt无法直接给静态方法注入依赖。最稳妥的方式是把格式化逻辑封装成一个支持依赖注入的工具类,再让扩展函数调用这个工具类:

class CurrencyFormatter @Inject constructor(
    private val numberFormat: NumberFormat
) {
    init {
        // 初始化配置,避免每次调用重复设置
        numberFormat.maximumFractionDigits = 0
    }

    fun formatInt(value: Int): String {
        return numberFormat.format(value)
    }
}

// 扩展函数调用工具类
fun Int.asCurrency(formatter: CurrencyFormatter): String {
    return formatter.formatInt(this)
}

在需要调用的地方(比如RecyclerView的Adapter),先通过Hilt注入CurrencyFormatter实例,再调用扩展函数时传入该实例即可。

2. 通过Hilt入口点获取依赖(适配特殊场景)

如果某些场景下无法直接注入工具类(比如纯顶层函数场景),可以用Hilt的@EntryPoint获取依赖实例:

// 定义入口点接口
@EntryPoint
@InstallIn(SingletonComponent::class)
interface FormatterEntryPoint {
    fun getCurrencyFormatter(): NumberFormat
}

// 扩展函数中通过入口点获取实例
fun Int.asCurrency(context: Context): String {
    val entryPoint = EntryPointAccessors.fromApplication(
        context.applicationContext,
        FormatterEntryPoint::class.java
    )
    val formatter = entryPoint.getCurrencyFormatter()
    formatter.maximumFractionDigits = 0
    return formatter.format(this)
}

调用时传入上下文即可,但这种方式会增加代码与Hilt的耦合度,建议仅在必要时使用。

3. 普通函数的注入方式

普通函数如果是类的成员函数,可以直接通过构造注入或字段注入依赖:

class NumberService @Inject constructor(
    private val formatter: NumberFormat
) {
    fun formatCurrency(value: Int): String {
        formatter.maximumFractionDigits = 0
        return formatter.format(value)
    }
}

如果是顶层函数,同样无法直接注入,建议要么封装到类中,要么通过上述入口点方式获取依赖。

内容的提问来源于stack exchange,提问作者Alraj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 20:52:29