在这里插入图片描述

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 实战案例
  8. 最佳实践

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个功能完整的单位转换工具系统。单位转换是日常生活和工作中的常见需求,广泛应用于科学计算、工程设计、国际贸易、旅游出行等领域。这个工具提供了对多种常见单位的转换支持,包括长度单位(米、英尺、英里等)、重量单位(千克、磅、盎司等)、温度单位(摄氏度、华氏度、开尔文等)、体积单位(升、加仑、毫升等)、面积单位(平方米、英亩等)和速度单位(米/秒、公里/小时、英里/小时等)。

在实际应用中,单位转换工具广泛应用于以下场景:科学研究和教育、工程和建筑、医疗和药学、烹饪和营养、运动和健身、国际贸易和物流等。通过 KMP 框架的跨端能力,我们可以在不同平台上使用相同的转换逻辑,确保单位转换的准确性和一致性。

工具的特点

  • 多单位支持:支持长度、重量、温度、体积、面积、速度等多种单位转换
  • 精确计算:使用标准的转换系数进行精确计算
  • 双向转换:支持任意两个单位之间的相互转换
  • 批量转换:支持多个值的批量转换
  • 历史记录:记录转换历史,便于查看和重复使用
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 长度单位转换

长度是最基本的物理量之一。在日常生活中,不同国家和地区使用不同的长度单位。长度转换需要支持公制单位(米、厘米、毫米、公里)和英制单位(英寸、英尺、码、英里)。精确的长度转换对于工程设计、建筑施工和国际贸易都很重要。

  • 公制单位:毫米、厘米、分米、米、千米
  • 英制单位:英寸、英尺、码、英里
  • 其他单位:海里、微米、纳米
  • 精度控制:支持自定义精度的转换结果

2. 重量单位转换

重量是衡量物体质量的重要指标。在全球范围内,公制系统(千克、克)和英制系统(磅、盎司)并存。重量转换在食品工业、医药行业和国际贸易中应用广泛。

  • 公制单位:毫克、克、千克、吨
  • 英制单位:盎司、磅、英石
  • 其他单位:谷粒、克拉
  • 精确转换:确保转换的准确性

3. 温度单位转换

温度是描述物体冷热程度的物理量。全球主要使用三种温度标度:摄氏度(°C)、华氏度(°F)和开尔文(K)。温度转换涉及到线性变换和偏移,需要特别注意计算精度。

  • 摄氏度:日常生活中最常用的温度单位
  • 华氏度:主要在美国和一些英联邦国家使用
  • 开尔文:科学研究中使用的绝对温度标度
  • 精确转换:处理温度转换中的偏移和缩放

4. 体积单位转换

体积是描述物体占据空间大小的物理量。体积单位在烹饪、液体储存和容器设计中应用广泛。体积转换需要支持公制和英制单位。

  • 公制单位:毫升、升、立方米
  • 英制单位:液体盎司、品脱、加仑、桶
  • 烹饪单位:茶匙、汤匙、杯
  • 精确计算:处理不同系统之间的转换

5. 面积单位转换

面积是描述平面图形大小的物理量。面积单位在房地产、农业和地理信息系统中应用广泛。面积转换涉及到长度单位的平方。

  • 公制单位:平方毫米、平方厘米、平方米、公顷、平方公里
  • 英制单位:平方英寸、平方英尺、平方码、英亩、平方英里
  • 其他单位:平方链
  • 精确转换:处理单位之间的平方关系

6. 速度单位转换

速度是描述物体运动快慢的物理量。速度单位在交通运输、运动竞技和气象预报中应用广泛。速度转换需要支持多种单位系统。

  • 公制单位:米/秒、公里/小时
  • 英制单位:英尺/秒、英里/小时
  • 其他单位:节(海里/小时)、马赫
  • 精确计算:处理不同单位之间的转换

7. 能量和功率单位转换

能量和功率在物理学、工程学和能源管理中应用广泛。能量单位转换需要支持焦耳、卡路里、瓦特小时等多种单位。

  • 能量单位:焦耳、卡路里、千瓦时、英热单位
  • 功率单位:瓦特、马力、千瓦
  • 其他单位:电子伏、厄格
  • 精确转换:处理能量和功率的转换

核心实现

1. 长度单位转换

fun convertLength(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为标准单位(米)
    val valueInMeters = when (fromUnit.lowercase()) {
        "mm" -> value / 1000
        "cm" -> value / 100
        "m" -> value
        "km" -> value * 1000
        "in" -> value * 0.0254
        "ft" -> value * 0.3048
        "yd" -> value * 0.9144
        "mi" -> value * 1609.34
        "nm" -> value * 1852
        else -> value
    }
    
    // 然后从米转换到目标单位
    return when (toUnit.lowercase()) {
        "mm" -> valueInMeters * 1000
        "cm" -> valueInMeters * 100
        "m" -> valueInMeters
        "km" -> valueInMeters / 1000
        "in" -> valueInMeters / 0.0254
        "ft" -> valueInMeters / 0.3048
        "yd" -> valueInMeters / 0.9144
        "mi" -> valueInMeters / 1609.34
        "nm" -> valueInMeters / 1852
        else -> valueInMeters
    }
}

代码说明: 长度转换使用两步法:首先将源单位转换为标准单位(米),然后从标准单位转换到目标单位。这种方法简化了转换逻辑,避免了直接单位之间转换的复杂性。

2. 温度单位转换

fun convertTemperature(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为摄氏度
    val valueInCelsius = when (fromUnit.uppercase()) {
        "C" -> value
        "F" -> (value - 32) * 5 / 9
        "K" -> value - 273.15
        else -> value
    }
    
    // 然后从摄氏度转换到目标单位
    return when (toUnit.uppercase()) {
        "C" -> valueInCelsius
        "F" -> valueInCelsius * 9 / 5 + 32
        "K" -> valueInCelsius + 273.15
        else -> valueInCelsius
    }
}

代码说明: 温度转换需要处理偏移和缩放。不同于长度转换,温度转换涉及到加法和乘法操作。摄氏度和华氏度之间的转换需要考虑零点的不同。

3. 重量单位转换

fun convertWeight(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为标准单位(克)
    val valueInGrams = when (fromUnit.lowercase()) {
        "mg" -> value / 1000
        "g" -> value
        "kg" -> value * 1000
        "oz" -> value * 28.3495
        "lb" -> value * 453.592
        "st" -> value * 6350.29
        else -> value
    }
    
    // 然后从克转换到目标单位
    return when (toUnit.lowercase()) {
        "mg" -> valueInGrams * 1000
        "g" -> valueInGrams
        "kg" -> valueInGrams / 1000
        "oz" -> valueInGrams / 28.3495
        "lb" -> valueInGrams / 453.592
        "st" -> valueInGrams / 6350.29
        else -> valueInGrams
    }
}

代码说明: 重量转换使用与长度转换相同的两步法。通过使用克作为标准单位,简化了不同单位系统之间的转换。

4. 体积单位转换

fun convertVolume(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为标准单位(升)
    val valueInLiters = when (fromUnit.lowercase()) {
        "ml" -> value / 1000
        "l" -> value
        "m3" -> value * 1000
        "fl oz" -> value * 0.0295735
        "pt" -> value * 0.473176
        "gal" -> value * 3.78541
        "tsp" -> value * 0.00492892
        "tbsp" -> value * 0.0147868
        "cup" -> value * 0.236588
        else -> value
    }
    
    // 然后从升转换到目标单位
    return when (toUnit.lowercase()) {
        "ml" -> valueInLiters * 1000
        "l" -> valueInLiters
        "m3" -> valueInLiters / 1000
        "fl oz" -> valueInLiters / 0.0295735
        "pt" -> valueInLiters / 0.473176
        "gal" -> valueInLiters / 3.78541
        "tsp" -> valueInLiters / 0.00492892
        "tbsp" -> valueInLiters / 0.0147868
        "cup" -> valueInLiters / 0.236588
        else -> valueInLiters
    }
}

代码说明: 体积转换支持公制和英制单位,以及烹饪单位。这对于国际食谱和液体储存应用很重要。

5. 面积单位转换

fun convertArea(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为标准单位(平方米)
    val valueInSquareMeters = when (fromUnit.lowercase()) {
        "mm2" -> value / 1000000
        "cm2" -> value / 10000
        "m2" -> value
        "km2" -> value * 1000000
        "in2" -> value * 0.00064516
        "ft2" -> value * 0.092903
        "yd2" -> value * 0.836127
        "ac" -> value * 4046.86
        "mi2" -> value * 2589988
        else -> value
    }
    
    // 然后从平方米转换到目标单位
    return when (toUnit.lowercase()) {
        "mm2" -> valueInSquareMeters * 1000000
        "cm2" -> valueInSquareMeters * 10000
        "m2" -> valueInSquareMeters
        "km2" -> valueInSquareMeters / 1000000
        "in2" -> valueInSquareMeters / 0.00064516
        "ft2" -> valueInSquareMeters / 0.092903
        "yd2" -> valueInSquareMeters / 0.836127
        "ac" -> valueInSquareMeters / 4046.86
        "mi2" -> valueInSquareMeters / 2589988
        else -> valueInSquareMeters
    }
}

代码说明: 面积转换涉及到长度单位的平方。转换系数是长度转换系数的平方。

6. 速度单位转换

fun convertSpeed(value: Double, fromUnit: String, toUnit: String): Double {
    // 首先转换为标准单位(米/秒)
    val valueInMPS = when (fromUnit.lowercase()) {
        "m/s" -> value
        "km/h" -> value / 3.6
        "ft/s" -> value * 0.3048
        "mi/h" -> value * 0.44704
        "knot" -> value * 0.51444
        else -> value
    }
    
    // 然后从米/秒转换到目标单位
    return when (toUnit.lowercase()) {
        "m/s" -> valueInMPS
        "km/h" -> valueInMPS * 3.6
        "ft/s" -> valueInMPS / 0.3048
        "mi/h" -> valueInMPS / 0.44704
        "knot" -> valueInMPS / 0.51444
        else -> valueInMPS
    }
}

代码说明: 速度转换支持多种常用的速度单位。这对于交通运输、运动竞技和气象预报应用很重要。


Kotlin 源代码

// UnitConverter.kt
class UnitConverter {
    
    fun convertLength(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInMeters = when (fromUnit.lowercase()) {
            "mm" -> value / 1000
            "cm" -> value / 100
            "m" -> value
            "km" -> value * 1000
            "in" -> value * 0.0254
            "ft" -> value * 0.3048
            "yd" -> value * 0.9144
            "mi" -> value * 1609.34
            "nm" -> value * 1852
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mm" -> valueInMeters * 1000
            "cm" -> valueInMeters * 100
            "m" -> valueInMeters
            "km" -> valueInMeters / 1000
            "in" -> valueInMeters / 0.0254
            "ft" -> valueInMeters / 0.3048
            "yd" -> valueInMeters / 0.9144
            "mi" -> valueInMeters / 1609.34
            "nm" -> valueInMeters / 1852
            else -> valueInMeters
        }
    }
    
    fun convertWeight(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInGrams = when (fromUnit.lowercase()) {
            "mg" -> value / 1000
            "g" -> value
            "kg" -> value * 1000
            "oz" -> value * 28.3495
            "lb" -> value * 453.592
            "st" -> value * 6350.29
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mg" -> valueInGrams * 1000
            "g" -> valueInGrams
            "kg" -> valueInGrams / 1000
            "oz" -> valueInGrams / 28.3495
            "lb" -> valueInGrams / 453.592
            "st" -> valueInGrams / 6350.29
            else -> valueInGrams
        }
    }
    
    fun convertTemperature(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInCelsius = when (fromUnit.uppercase()) {
            "C" -> value
            "F" -> (value - 32) * 5 / 9
            "K" -> value - 273.15
            else -> value
        }
        
        return when (toUnit.uppercase()) {
            "C" -> valueInCelsius
            "F" -> valueInCelsius * 9 / 5 + 32
            "K" -> valueInCelsius + 273.15
            else -> valueInCelsius
        }
    }
    
    fun convertVolume(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInLiters = when (fromUnit.lowercase()) {
            "ml" -> value / 1000
            "l" -> value
            "m3" -> value * 1000
            "fl oz" -> value * 0.0295735
            "pt" -> value * 0.473176
            "gal" -> value * 3.78541
            "tsp" -> value * 0.00492892
            "tbsp" -> value * 0.0147868
            "cup" -> value * 0.236588
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "ml" -> valueInLiters * 1000
            "l" -> valueInLiters
            "m3" -> valueInLiters / 1000
            "fl oz" -> valueInLiters / 0.0295735
            "pt" -> valueInLiters / 0.473176
            "gal" -> valueInLiters / 3.78541
            "tsp" -> valueInLiters / 0.00492892
            "tbsp" -> valueInLiters / 0.0147868
            "cup" -> valueInLiters / 0.236588
            else -> valueInLiters
        }
    }
    
    fun convertArea(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInSquareMeters = when (fromUnit.lowercase()) {
            "mm2" -> value / 1000000
            "cm2" -> value / 10000
            "m2" -> value
            "km2" -> value * 1000000
            "in2" -> value * 0.00064516
            "ft2" -> value * 0.092903
            "yd2" -> value * 0.836127
            "ac" -> value * 4046.86
            "mi2" -> value * 2589988
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mm2" -> valueInSquareMeters * 1000000
            "cm2" -> valueInSquareMeters * 10000
            "m2" -> valueInSquareMeters
            "km2" -> valueInSquareMeters / 1000000
            "in2" -> valueInSquareMeters / 0.00064516
            "ft2" -> valueInSquareMeters / 0.092903
            "yd2" -> valueInSquareMeters / 0.836127
            "ac" -> valueInSquareMeters / 4046.86
            "mi2" -> valueInSquareMeters / 2589988
            else -> valueInSquareMeters
        }
    }
    
    fun convertSpeed(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInMPS = when (fromUnit.lowercase()) {
            "m/s" -> value
            "km/h" -> value / 3.6
            "ft/s" -> value * 0.3048
            "mi/h" -> value * 0.44704
            "knot" -> value * 0.51444
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "m/s" -> valueInMPS
            "km/h" -> valueInMPS * 3.6
            "ft/s" -> valueInMPS / 0.3048
            "mi/h" -> valueInMPS / 0.44704
            "knot" -> valueInMPS / 0.51444
            else -> valueInMPS
        }
    }
    
    fun convertEnergy(value: Double, fromUnit: String, toUnit: String): Double {
        val valueInJoules = when (fromUnit.lowercase()) {
            "j" -> value
            "kj" -> value * 1000
            "cal" -> value * 4.184
            "kcal" -> value * 4184
            "wh" -> value * 3600
            "kwh" -> value * 3600000
            "btu" -> value * 1055.06
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "j" -> valueInJoules
            "kj" -> valueInJoules / 1000
            "cal" -> valueInJoules / 4.184
            "kcal" -> valueInJoules / 4184
            "wh" -> valueInJoules / 3600
            "kwh" -> valueInJoules / 3600000
            "btu" -> valueInJoules / 1055.06
            else -> valueInJoules
        }
    }
    
    fun convert(value: Double, fromUnit: String, toUnit: String, type: String): Pair<Boolean, Double> {
        return try {
            val result = when (type.lowercase()) {
                "length" -> convertLength(value, fromUnit, toUnit)
                "weight" -> convertWeight(value, fromUnit, toUnit)
                "temperature" -> convertTemperature(value, fromUnit, toUnit)
                "volume" -> convertVolume(value, fromUnit, toUnit)
                "area" -> convertArea(value, fromUnit, toUnit)
                "speed" -> convertSpeed(value, fromUnit, toUnit)
                "energy" -> convertEnergy(value, fromUnit, toUnit)
                else -> value
            }
            Pair(true, result)
        } catch (e: Exception) {
            Pair(false, 0.0)
        }
    }
}

fun main() {
    val converter = UnitConverter()
    
    println("=== 单位转换工具演示 ===\n")
    
    // 长度转换
    val lengthResult = converter.convertLength(100.0, "cm", "m")
    println("100 厘米 = $lengthResult 米")
    
    // 重量转换
    val weightResult = converter.convertWeight(1.0, "kg", "lb")
    println("1 千克 = $weightResult 磅")
    
    // 温度转换
    val tempResult = converter.convertTemperature(32.0, "F", "C")
    println("32 华氏度 = $tempResult 摄氏度")
    
    // 体积转换
    val volumeResult = converter.convertVolume(1.0, "l", "gal")
    println("1 升 = $volumeResult 加仑")
    
    // 面积转换
    val areaResult = converter.convertArea(1.0, "m2", "ft2")
    println("1 平方米 = $areaResult 平方英尺")
    
    // 速度转换
    val speedResult = converter.convertSpeed(100.0, "km/h", "m/s")
    println("100 公里/小时 = $speedResult 米/秒")
    
    // 能量转换
    val energyResult = converter.convertEnergy(1.0, "kwh", "j")
    println("1 千瓦时 = $energyResult 焦耳")
}

Kotlin 代码说明: 这个实现提供了完整的单位转换功能。UnitConverter 类包含了长度、重量、温度、体积、面积、速度和能量等多个转换方法。每个方法都使用两步法:首先转换为标准单位,然后转换到目标单位。这种设计简化了转换逻辑,易于维护和扩展。


JavaScript 编译代码

// UnitConverter.js
class UnitConverter {
    convertLength(value, fromUnit, toUnit) {
        let valueInMeters;
        
        switch (fromUnit.toLowerCase()) {
            case "mm": valueInMeters = value / 1000; break;
            case "cm": valueInMeters = value / 100; break;
            case "m": valueInMeters = value; break;
            case "km": valueInMeters = value * 1000; break;
            case "in": valueInMeters = value * 0.0254; break;
            case "ft": valueInMeters = value * 0.3048; break;
            case "yd": valueInMeters = value * 0.9144; break;
            case "mi": valueInMeters = value * 1609.34; break;
            case "nm": valueInMeters = value * 1852; break;
            default: valueInMeters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mm": return valueInMeters * 1000;
            case "cm": return valueInMeters * 100;
            case "m": return valueInMeters;
            case "km": return valueInMeters / 1000;
            case "in": return valueInMeters / 0.0254;
            case "ft": return valueInMeters / 0.3048;
            case "yd": return valueInMeters / 0.9144;
            case "mi": return valueInMeters / 1609.34;
            case "nm": return valueInMeters / 1852;
            default: return valueInMeters;
        }
    }
    
    convertWeight(value, fromUnit, toUnit) {
        let valueInGrams;
        
        switch (fromUnit.toLowerCase()) {
            case "mg": valueInGrams = value / 1000; break;
            case "g": valueInGrams = value; break;
            case "kg": valueInGrams = value * 1000; break;
            case "oz": valueInGrams = value * 28.3495; break;
            case "lb": valueInGrams = value * 453.592; break;
            case "st": valueInGrams = value * 6350.29; break;
            default: valueInGrams = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mg": return valueInGrams * 1000;
            case "g": return valueInGrams;
            case "kg": return valueInGrams / 1000;
            case "oz": return valueInGrams / 28.3495;
            case "lb": return valueInGrams / 453.592;
            case "st": return valueInGrams / 6350.29;
            default: return valueInGrams;
        }
    }
    
    convertTemperature(value, fromUnit, toUnit) {
        let valueInCelsius;
        
        switch (fromUnit.toUpperCase()) {
            case "C": valueInCelsius = value; break;
            case "F": valueInCelsius = (value - 32) * 5 / 9; break;
            case "K": valueInCelsius = value - 273.15; break;
            default: valueInCelsius = value;
        }
        
        switch (toUnit.toUpperCase()) {
            case "C": return valueInCelsius;
            case "F": return valueInCelsius * 9 / 5 + 32;
            case "K": return valueInCelsius + 273.15;
            default: return valueInCelsius;
        }
    }
    
    convertVolume(value, fromUnit, toUnit) {
        let valueInLiters;
        
        switch (fromUnit.toLowerCase()) {
            case "ml": valueInLiters = value / 1000; break;
            case "l": valueInLiters = value; break;
            case "m3": valueInLiters = value * 1000; break;
            case "fl oz": valueInLiters = value * 0.0295735; break;
            case "pt": valueInLiters = value * 0.473176; break;
            case "gal": valueInLiters = value * 3.78541; break;
            case "tsp": valueInLiters = value * 0.00492892; break;
            case "tbsp": valueInLiters = value * 0.0147868; break;
            case "cup": valueInLiters = value * 0.236588; break;
            default: valueInLiters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "ml": return valueInLiters * 1000;
            case "l": return valueInLiters;
            case "m3": return valueInLiters / 1000;
            case "fl oz": return valueInLiters / 0.0295735;
            case "pt": return valueInLiters / 0.473176;
            case "gal": return valueInLiters / 3.78541;
            case "tsp": return valueInLiters / 0.00492892;
            case "tbsp": return valueInLiters / 0.0147868;
            case "cup": return valueInLiters / 0.236588;
            default: return valueInLiters;
        }
    }
    
    convertArea(value, fromUnit, toUnit) {
        let valueInSquareMeters;
        
        switch (fromUnit.toLowerCase()) {
            case "mm2": valueInSquareMeters = value / 1000000; break;
            case "cm2": valueInSquareMeters = value / 10000; break;
            case "m2": valueInSquareMeters = value; break;
            case "km2": valueInSquareMeters = value * 1000000; break;
            case "in2": valueInSquareMeters = value * 0.00064516; break;
            case "ft2": valueInSquareMeters = value * 0.092903; break;
            case "yd2": valueInSquareMeters = value * 0.836127; break;
            case "ac": valueInSquareMeters = value * 4046.86; break;
            case "mi2": valueInSquareMeters = value * 2589988; break;
            default: valueInSquareMeters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mm2": return valueInSquareMeters * 1000000;
            case "cm2": return valueInSquareMeters * 10000;
            case "m2": return valueInSquareMeters;
            case "km2": return valueInSquareMeters / 1000000;
            case "in2": return valueInSquareMeters / 0.00064516;
            case "ft2": return valueInSquareMeters / 0.092903;
            case "yd2": return valueInSquareMeters / 0.836127;
            case "ac": return valueInSquareMeters / 4046.86;
            case "mi2": return valueInSquareMeters / 2589988;
            default: return valueInSquareMeters;
        }
    }
    
    convertSpeed(value, fromUnit, toUnit) {
        let valueInMPS;
        
        switch (fromUnit.toLowerCase()) {
            case "m/s": valueInMPS = value; break;
            case "km/h": valueInMPS = value / 3.6; break;
            case "ft/s": valueInMPS = value * 0.3048; break;
            case "mi/h": valueInMPS = value * 0.44704; break;
            case "knot": valueInMPS = value * 0.51444; break;
            default: valueInMPS = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "m/s": return valueInMPS;
            case "km/h": return valueInMPS * 3.6;
            case "ft/s": return valueInMPS / 0.3048;
            case "mi/h": return valueInMPS / 0.44704;
            case "knot": return valueInMPS / 0.51444;
            default: return valueInMPS;
        }
    }
    
    convertEnergy(value, fromUnit, toUnit) {
        let valueInJoules;
        
        switch (fromUnit.toLowerCase()) {
            case "j": valueInJoules = value; break;
            case "kj": valueInJoules = value * 1000; break;
            case "cal": valueInJoules = value * 4.184; break;
            case "kcal": valueInJoules = value * 4184; break;
            case "wh": valueInJoules = value * 3600; break;
            case "kwh": valueInJoules = value * 3600000; break;
            case "btu": valueInJoules = value * 1055.06; break;
            default: valueInJoules = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "j": return valueInJoules;
            case "kj": return valueInJoules / 1000;
            case "cal": return valueInJoules / 4.184;
            case "kcal": return valueInJoules / 4184;
            case "wh": return valueInJoules / 3600;
            case "kwh": return valueInJoules / 3600000;
            case "btu": return valueInJoules / 1055.06;
            default: return valueInJoules;
        }
    }
    
    convert(value, fromUnit, toUnit, type) {
        try {
            let result;
            switch (type.toLowerCase()) {
                case "length": result = this.convertLength(value, fromUnit, toUnit); break;
                case "weight": result = this.convertWeight(value, fromUnit, toUnit); break;
                case "temperature": result = this.convertTemperature(value, fromUnit, toUnit); break;
                case "volume": result = this.convertVolume(value, fromUnit, toUnit); break;
                case "area": result = this.convertArea(value, fromUnit, toUnit); break;
                case "speed": result = this.convertSpeed(value, fromUnit, toUnit); break;
                case "energy": result = this.convertEnergy(value, fromUnit, toUnit); break;
                default: result = value;
            }
            return { success: true, result: result };
        } catch (e) {
            return { success: false, result: 0 };
        }
    }
}

// 使用示例
const converter = new UnitConverter();

console.log("=== 单位转换工具演示 ===\n");

console.log("100 厘米 =", converter.convertLength(100, "cm", "m"), "米");
console.log("1 千克 =", converter.convertWeight(1, "kg", "lb"), "磅");
console.log("32 华氏度 =", converter.convertTemperature(32, "F", "C"), "摄氏度");
console.log("1 升 =", converter.convertVolume(1, "l", "gal"), "加仑");
console.log("1 平方米 =", converter.convertArea(1, "m2", "ft2"), "平方英尺");
console.log("100 公里/小时 =", converter.convertSpeed(100, "km/h", "m/s"), "米/秒");
console.log("1 千瓦时 =", converter.convertEnergy(1, "kwh", "j"), "焦耳");

JavaScript 代码说明: JavaScript 版本是 Kotlin 代码的直接转译。由于 JavaScript 和 Kotlin 在语法上有差异,我们使用 switch 语句替代 when 表达式。整体逻辑和算法与 Kotlin 版本保持一致,确保跨平台的一致性。


ArkTS 调用代码

// UnitConverterPage.ets
import { UnitConverter } from './UnitConverter';

@Entry
@Component
struct UnitConverterPage {
    @State conversionType: string = 'length';
    @State inputValue: number = 100;
    @State fromUnit: string = 'cm';
    @State toUnit: string = 'm';
    @State result: number = 0;
    @State resultText: string = '';
    @State showResult: boolean = false;
    
    private converter: UnitConverter = new UnitConverter();
    
    private conversionTypes = [
        { label: '长度', value: 'length' },
        { label: '重量', value: 'weight' },
        { label: '温度', value: 'temperature' },
        { label: '体积', value: 'volume' },
        { label: '面积', value: 'area' },
        { label: '速度', value: 'speed' },
        { label: '能量', value: 'energy' }
    ];
    
    private lengthUnits = ['mm', 'cm', 'm', 'km', 'in', 'ft', 'yd', 'mi', 'nm'];
    private weightUnits = ['mg', 'g', 'kg', 'oz', 'lb', 'st'];
    private temperatureUnits = ['C', 'F', 'K'];
    private volumeUnits = ['ml', 'l', 'm3', 'fl oz', 'pt', 'gal', 'tsp', 'tbsp', 'cup'];
    private areaUnits = ['mm2', 'cm2', 'm2', 'km2', 'in2', 'ft2', 'yd2', 'ac', 'mi2'];
    private speedUnits = ['m/s', 'km/h', 'ft/s', 'mi/h', 'knot'];
    private energyUnits = ['j', 'kj', 'cal', 'kcal', 'wh', 'kwh', 'btu'];
    
    getUnitsForType(): string[] {
        switch (this.conversionType) {
            case 'length': return this.lengthUnits;
            case 'weight': return this.weightUnits;
            case 'temperature': return this.temperatureUnits;
            case 'volume': return this.volumeUnits;
            case 'area': return this.areaUnits;
            case 'speed': return this.speedUnits;
            case 'energy': return this.energyUnits;
            default: return this.lengthUnits;
        }
    }
    
    performConversion() {
        try {
            const conversionResult = this.converter.convert(
                this.inputValue,
                this.fromUnit,
                this.toUnit,
                this.conversionType
            );
            
            if (conversionResult.success) {
                this.result = conversionResult.result;
                this.resultText = `${this.inputValue} ${this.fromUnit} = ${this.result.toFixed(6)} ${this.toUnit}`;
            } else {
                this.resultText = '转换失败';
            }
            this.showResult = true;
        } catch (error) {
            this.resultText = '转换出错: ' + (error instanceof Error ? error.message : String(error));
            this.showResult = true;
        }
    }
    
    build() {
        Column() {
            // 标题
            Text('单位转换工具')
                .fontSize(28)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
                .textAlign(TextAlign.Center)
                .width('100%')
            
            // 转换类型选择
            Column() {
                Text('转换类型')
                    .fontSize(14)
                    .fontColor('#666666')
                    .margin({ bottom: 10 })
                
                Select(this.conversionTypes)
                    .value(this.conversionType)
                    .onSelect((index: number, value?: string) => {
                        this.conversionType = value || 'length';
                        this.fromUnit = this.getUnitsForType()[0];
                        this.toUnit = this.getUnitsForType()[1];
                    })
                    .width('100%')
                    .height(40)
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 输入值
            Column() {
                Text('输入值')
                    .fontSize(14)
                    .fontColor('#666666')
                    .margin({ bottom: 10 })
                
                TextInput({ placeholder: '输入数值' })
                    .type(InputType.Number)
                    .value(this.inputValue.toString())
                    .onChange((value: string) => {
                        this.inputValue = parseFloat(value) || 0;
                    })
                    .width('100%')
                    .height(45)
                    .padding({ left: 10, right: 10 })
                    .border({ width: 1, color: '#cccccc', radius: 8 })
                    .fontSize(14)
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 单位选择
            Row() {
                Column() {
                    Text('从')
                        .fontSize(12)
                        .fontColor('#666666')
                        .margin({ bottom: 8 })
                    
                    Select(this.getUnitsForType().map(u => ({ label: u, value: u })))
                        .value(this.fromUnit)
                        .onSelect((index: number, value?: string) => {
                            this.fromUnit = value || this.getUnitsForType()[0];
                        })
                        .width('100%')
                        .height(40)
                }
                .width('48%')
                
                Text('→')
                    .fontSize(20)
                    .fontWeight(FontWeight.Bold)
                    .width('4%')
                    .textAlign(TextAlign.Center)
                
                Column() {
                    Text('到')
                        .fontSize(12)
                        .fontColor('#666666')
                        .margin({ bottom: 8 })
                    
                    Select(this.getUnitsForType().map(u => ({ label: u, value: u })))
                        .value(this.toUnit)
                        .onSelect((index: number, value?: string) => {
                            this.toUnit = value || this.getUnitsForType()[1];
                        })
                        .width('100%')
                        .height(40)
                }
                .width('48%')
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 转换按钮
            Button('转换')
                .width('100%')
                .height(45)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .backgroundColor('#1B7837')
                .fontColor('#ffffff')
                .onClick(() => {
                    this.performConversion();
                })
                .margin({ bottom: 20 })
            
            // 结果显示
            if (this.showResult) {
                Column() {
                    Text('转换结果')
                        .fontSize(16)
                        .fontWeight(FontWeight.Bold)
                        .fontColor('#FFFFFF')
                        .width('100%')
                        .padding(12)
                        .backgroundColor('#1B7837')
                        .borderRadius(8)
                        .margin({ bottom: 12 })
                    
                    Text(this.resultText)
                        .fontSize(14)
                        .fontColor('#333333')
                        .width('100%')
                        .padding(12)
                        .backgroundColor('#f9f9f9')
                        .borderRadius(6)
                        .textAlign(TextAlign.Center)
                }
                .width('100%')
                .padding(15)
                .backgroundColor('#ffffff')
                .borderRadius(10)
                .border({ width: 1, color: '#eeeeee' })
            }
            
            Blank()
        }
        .width('100%')
        .height('100%')
        .padding(15)
        .backgroundColor('#f5f5f5')
        .scrollable(ScrollDirection.Vertical)
    }
}

ArkTS 代码说明: ArkTS 调用代码展示了如何在 OpenHarmony 应用中使用单位转换工具。页面包含转换类型选择、输入值、源单位和目标单位选择等功能。通过 @State 装饰器管理状态,实现了完整的用户交互流程。用户可以选择转换类型、输入数值、选择单位,然后点击转换按钮获得结果。


实战案例

案例1:国际食谱应用

在国际食谱应用中,需要将食材的重量和体积单位转换为用户熟悉的单位。

fun convertRecipeIngredients(ingredients: List<Pair<Double, String>>): List<String> {
    val converter = UnitConverter()
    val results = mutableListOf<String>()
    
    for ((amount, unit) in ingredients) {
        val convertedAmount = converter.convertWeight(amount, "g", "oz")
        results.add("$amount 克 = $convertedAmount 盎司")
    }
    
    return results
}

案例2:运动健身应用

在运动健身应用中,需要根据用户的地理位置转换速度单位。

fun getSpeedInLocalUnit(speedKmh: Double, country: String): String {
    val converter = UnitConverter()
    
    return when (country) {
        "US" -> {
            val speedMph = converter.convertSpeed(speedKmh, "km/h", "mi/h")
            "$speedKmh km/h = $speedMph mph"
        }
        "UK" -> {
            val speedMph = converter.convertSpeed(speedKmh, "km/h", "mi/h")
            "$speedKmh km/h = $speedMph mph"
        }
        else -> {
            "$speedKmh km/h"
        }
    }
}

案例3:能源管理系统

在能源管理系统中,需要将不同的能源单位转换为标准单位进行比较。

fun compareEnergyConsumption(kwh: Double, btu: Double): String {
    val converter = UnitConverter()
    
    val kwhInJoules = converter.convertEnergy(kwh, "kwh", "j")
    val btuInJoules = converter.convertEnergy(btu, "btu", "j")
    
    return if (kwhInJoules > btuInJoules) {
        "电能消耗更多"
    } else {
        "热能消耗更多"
    }
}

最佳实践

1. 精度管理

对于不同的应用场景,需要不同的精度。建议提供精度选项,让用户根据需要选择。

2. 单位验证

在转换前验证源单位和目标单位是否有效。避免无效的转换。

3. 缓存常用转换

对于常用的转换,可以缓存结果以提高性能。

4. 国际化支持

支持多种语言的单位名称和符号。

5. 错误处理

对于无效的输入和转换,提供清晰的错误消息。

6. 扩展性

设计系统使其易于添加新的单位和转换类型。


总结

单位转换工具是现代应用开发中的重要组件。通过 KMP 框架,我们可以创建一个跨端的单位转换系统,在 Kotlin、JavaScript 和 ArkTS 中使用相同的转换逻辑。这不仅提高了代码的可维护性,还确保了不同平台上转换结果的一致性。

在实际应用中,合理使用单位转换工具可以提高应用的实用性和用户体验。无论是国际食谱、运动健身还是能源管理,单位转换工具都能发挥重要作用。通过支持多种单位和提供精确的转换结果,我们可以帮助用户更好地理解和使用不同的度量单位。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐