在这里插入图片描述

项目概述

随机数生成是现代应用开发中的基础需求。无论是在游戏开发、数据模拟、安全加密、统计分析还是算法测试中,都需要进行各种随机数生成操作。然而,不同的编程语言和平台对随机数的实现方式各不相同,这导致开发者需要在不同平台上重复编写类似的逻辑。

本文介绍一个基于 Kotlin Multiplatform (KMP) 和 OpenHarmony 平台的随机数生成工具库。这个工具库提供了一套完整的随机数生成能力,包括整数随机数、浮点数随机数、字符串随机数、UUID 生成等功能。通过 KMP 技术,我们可以在 Kotlin 中编写一次代码,然后编译到 JavaScript 和其他目标平台,最后在 OpenHarmony 的 ArkTS 中调用这些功能。

技术架构

多平台支持

  • Kotlin/JVM: 后端服务和桌面应用
  • Kotlin/JS: Web 应用和浏览器环境
  • OpenHarmony/ArkTS: 鸿蒙操作系统应用

核心功能模块

  1. 整数随机数: 生成指定范围内的随机整数
  2. 浮点数随机数: 生成指定范围内的随机浮点数
  3. 布尔随机数: 生成随机的真假值
  4. 字符串随机数: 生成随机字符串
  5. UUID 生成: 生成唯一标识符
  6. 随机数组: 生成随机数组
  7. 随机排列: 对数组进行随机排列
  8. 加权随机: 基于权重的随机选择

Kotlin 实现

核心随机数生成类

// 文件: src/commonMain/kotlin/RandomGenerator.kt

import kotlin.random.Random

/**
 * 随机数生成工具类
 * 提供各种随机数生成功能
 */
class RandomGenerator {
    
    private val random = Random
    
    /**
     * 生成指定范围内的随机整数
     * @param min 最小值(包含)
     * @param max 最大值(不包含)
     * @return 随机整数
     */
    fun nextInt(min: Int = 0, max: Int = 100): Int {
        return random.nextInt(min, max)
    }
    
    /**
     * 生成指定范围内的随机长整数
     * @param min 最小值(包含)
     * @param max 最大值(不包含)
     * @return 随机长整数
     */
    fun nextLong(min: Long = 0, max: Long = 1000): Long {
        return random.nextLong(min, max)
    }
    
    /**
     * 生成指定范围内的随机浮点数
     * @param min 最小值
     * @param max 最大值
     * @return 随机浮点数
     */
    fun nextDouble(min: Double = 0.0, max: Double = 1.0): Double {
        return min + random.nextDouble() * (max - min)
    }
    
    /**
     * 生成随机浮点数(0.0 到 1.0)
     * @return 随机浮点数
     */
    fun nextFloat(): Float {
        return random.nextFloat()
    }
    
    /**
     * 生成随机布尔值
     * @return 随机布尔值
     */
    fun nextBoolean(): Boolean {
        return random.nextBoolean()
    }
    
    /**
     * 生成随机字符串
     * @param length 字符串长度
     * @param charset 字符集
     * @return 随机字符串
     */
    fun nextString(length: Int = 10, charset: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"): String {
        return (1..length)
            .map { charset[random.nextInt(charset.length)] }
            .joinToString("")
    }
    
    /**
     * 生成随机数字字符串
     * @param length 字符串长度
     * @return 随机数字字符串
     */
    fun nextNumericString(length: Int = 6): String {
        return nextString(length, "0123456789")
    }
    
    /**
     * 生成随机 UUID
     * @return UUID 字符串
     */
    fun nextUUID(): String {
        val bytes = ByteArray(16)
        random.nextBytes(bytes)
        
        // 设置版本为 4(随机)
        bytes[6] = (bytes[6].toInt() and 0x0f or 0x40).toByte()
        // 设置变体
        bytes[8] = (bytes[8].toInt() and 0x3f or 0x80).toByte()
        
        return buildString {
            for (i in bytes.indices) {
                if (i == 4 || i == 6 || i == 8 || i == 10) {
                    append('-')
                }
                append(String.format("%02x", bytes[i]))
            }
        }
    }
    
    /**
     * 从列表中随机选择一个元素
     * @param list 列表
     * @return 随机选择的元素
     */
    fun <T> choice(list: List<T>): T {
        return list[random.nextInt(list.size)]
    }
    
    /**
     * 从列表中随机选择多个元素
     * @param list 列表
     * @param count 选择数量
     * @return 随机选择的元素列表
     */
    fun <T> choices(list: List<T>, count: Int): List<T> {
        return (1..count).map { choice(list) }
    }
    
    /**
     * 随机排列列表
     * @param list 列表
     * @return 随机排列后的列表
     */
    fun <T> shuffle(list: List<T>): List<T> {
        return list.shuffled(random)
    }
    
    /**
     * 生成随机整数数组
     * @param size 数组大小
     * @param min 最小值
     * @param max 最大值
     * @return 随机整数数组
     */
    fun nextIntArray(size: Int, min: Int = 0, max: Int = 100): List<Int> {
        return (1..size).map { nextInt(min, max) }
    }
    
    /**
     * 生成随机浮点数数组
     * @param size 数组大小
     * @param min 最小值
     * @param max 最大值
     * @return 随机浮点数数组
     */
    fun nextDoubleArray(size: Int, min: Double = 0.0, max: Double = 1.0): List<Double> {
        return (1..size).map { nextDouble(min, max) }
    }
    
    /**
     * 基于权重的随机选择
     * @param items 项目列表
     * @param weights 权重列表
     * @return 随机选择的项目
     */
    fun <T> weightedChoice(items: List<T>, weights: List<Double>): T {
        if (items.size != weights.size) {
            throw IllegalArgumentException("Items and weights must have the same size")
        }
        
        val totalWeight = weights.sum()
        var randomValue = random.nextDouble() * totalWeight
        
        for (i in items.indices) {
            randomValue -= weights[i]
            if (randomValue <= 0) {
                return items[i]
            }
        }
        
        return items.last()
    }
    
    /**
     * 生成随机颜色
     * @return RGB 颜色字符串
     */
    fun nextColor(): String {
        val r = nextInt(0, 256)
        val g = nextInt(0, 256)
        val b = nextInt(0, 256)
        return String.format("#%02X%02X%02X", r, g, b)
    }
    
    /**
     * 生成随机骰子结果
     * @param sides 骰子面数
     * @param count 骰子数量
     * @return 骰子结果列表
     */
    fun rollDice(sides: Int = 6, count: Int = 1): List<Int> {
        return (1..count).map { nextInt(1, sides + 1) }
    }
}

Kotlin 实现的核心特点

Kotlin 实现中的随机数生成功能充分利用了 Kotlin 标准库的 Random 类。整数随机数使用了 nextInt 方法,浮点数随机数使用了 nextDouble 方法。

字符串生成使用了字符集和循环来构建随机字符串。UUID 生成使用了字节数组和格式化来创建标准的 UUID 格式。

列表操作使用了 shuffled 方法来进行随机排列。权重随机选择使用了累积权重的方法来实现。

颜色生成使用了 RGB 值的随机组合。骰子模拟使用了指定范围的随机整数。

JavaScript 实现

编译后的 JavaScript 代码

// 文件: build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony.js
// (由 Kotlin 编译器自动生成)

/**
 * RandomGenerator 类的 JavaScript 版本
 * 通过 Kotlin/JS 编译器从 Kotlin 源代码生成
 */
class RandomGenerator {
  /**
   * 生成指定范围内的随机整数
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number} 随机整数
   */
  nextInt(min = 0, max = 100) {
    return Math.floor(Math.random() * (max - min)) + min;
  }

  /**
   * 生成指定范围内的随机浮点数
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number} 随机浮点数
   */
  nextDouble(min = 0.0, max = 1.0) {
    return min + Math.random() * (max - min);
  }

  /**
   * 生成随机浮点数
   * @returns {number} 随机浮点数
   */
  nextFloat() {
    return Math.random();
  }

  /**
   * 生成随机布尔值
   * @returns {boolean} 随机布尔值
   */
  nextBoolean() {
    return Math.random() > 0.5;
  }

  /**
   * 生成随机字符串
   * @param {number} length - 字符串长度
   * @param {string} charset - 字符集
   * @returns {string} 随机字符串
   */
  nextString(length = 10, charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
    let result = '';
    for (let i = 0; i < length; i++) {
      result += charset.charAt(Math.floor(Math.random() * charset.length));
    }
    return result;
  }

  /**
   * 生成随机数字字符串
   * @param {number} length - 字符串长度
   * @returns {string} 随机数字字符串
   */
  nextNumericString(length = 6) {
    return this.nextString(length, '0123456789');
  }

  /**
   * 生成随机 UUID
   * @returns {string} UUID 字符串
   */
  nextUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }

  /**
   * 从列表中随机选择一个元素
   * @param {Array} list - 列表
   * @returns {*} 随机选择的元素
   */
  choice(list) {
    return list[Math.floor(Math.random() * list.length)];
  }

  /**
   * 从列表中随机选择多个元素
   * @param {Array} list - 列表
   * @param {number} count - 选择数量
   * @returns {Array} 随机选择的元素列表
   */
  choices(list, count) {
    const result = [];
    for (let i = 0; i < count; i++) {
      result.push(this.choice(list));
    }
    return result;
  }

  /**
   * 随机排列列表
   * @param {Array} list - 列表
   * @returns {Array} 随机排列后的列表
   */
  shuffle(list) {
    const result = [...list];
    for (let i = result.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [result[i], result[j]] = [result[j], result[i]];
    }
    return result;
  }

  /**
   * 生成随机整数数组
   * @param {number} size - 数组大小
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number[]} 随机整数数组
   */
  nextIntArray(size, min = 0, max = 100) {
    const result = [];
    for (let i = 0; i < size; i++) {
      result.push(this.nextInt(min, max));
    }
    return result;
  }

  /**
   * 生成随机浮点数数组
   * @param {number} size - 数组大小
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number[]} 随机浮点数数组
   */
  nextDoubleArray(size, min = 0.0, max = 1.0) {
    const result = [];
    for (let i = 0; i < size; i++) {
      result.push(this.nextDouble(min, max));
    }
    return result;
  }

  /**
   * 基于权重的随机选择
   * @param {Array} items - 项目列表
   * @param {number[]} weights - 权重列表
   * @returns {*} 随机选择的项目
   */
  weightedChoice(items, weights) {
    if (items.length !== weights.length) {
      throw new Error('Items and weights must have the same size');
    }

    const totalWeight = weights.reduce((a, b) => a + b, 0);
    let randomValue = Math.random() * totalWeight;

    for (let i = 0; i < items.length; i++) {
      randomValue -= weights[i];
      if (randomValue <= 0) {
        return items[i];
      }
    }

    return items[items.length - 1];
  }

  /**
   * 生成随机颜色
   * @returns {string} RGB 颜色字符串
   */
  nextColor() {
    const r = this.nextInt(0, 256);
    const g = this.nextInt(0, 256);
    const b = this.nextInt(0, 256);
    return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`.toUpperCase();
  }

  /**
   * 生成随机骰子结果
   * @param {number} sides - 骰子面数
   * @param {number} count - 骰子数量
   * @returns {number[]} 骰子结果列表
   */
  rollDice(sides = 6, count = 1) {
    const result = [];
    for (let i = 0; i < count; i++) {
      result.push(this.nextInt(1, sides + 1));
    }
    return result;
  }
}

JavaScript 实现的特点

JavaScript 版本完全由 Kotlin/JS 编译器自动生成,确保了与 Kotlin 版本的行为完全一致。JavaScript 的 Math.random() 提供了基础的随机数生成。

Math.floor 用于生成整数,Math.random() * (max - min) + min 用于生成指定范围的随机数。UUID 生成使用了正则表达式替换的方法。

Fisher-Yates 算法用于实现列表的随机排列。权重随机选择使用了累积权重的方法。

ArkTS 调用代码

OpenHarmony 应用集成

// 文件: kmp_ceshiapp/entry/src/main/ets/pages/RandomGeneratorPage.ets

import { RandomGenerator } from '../../../../../../../build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony';

@Entry
@Component
struct RandomGeneratorPage {
  @State selectedOperation: string = 'int';
  @State minValue: string = '0';
  @State maxValue: string = '100';
  @State result: string = '';
  @State resultTitle: string = '';

  private randomGenerator = new RandomGenerator();

  private operations = [
    { name: '随机整数', value: 'int' },
    { name: '随机浮点数', value: 'double' },
    { name: '随机布尔值', value: 'boolean' },
    { name: '随机字符串', value: 'string' },
    { name: '随机 UUID', value: 'uuid' },
    { name: '随机颜色', value: 'color' },
    { name: '掷骰子', value: 'dice' },
    { name: '随机排列', value: 'shuffle' },
    { name: '随机数组', value: 'array' }
  ];

  build() {
    Column() {
      // 标题
      Text('🎲 随机数生成工具库')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .width('100%')
        .padding(20)
        .backgroundColor('#1A237E')
        .textAlign(TextAlign.Center)

      Scroll() {
        Column() {
          // 操作选择
          Column() {
            Text('选择操作')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ bottom: 12 })

            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.operations, (op: { name: string; value: string }) => {
                Button(op.name)
                  .layoutWeight(1)
                  .height(40)
                  .margin({ right: 8, bottom: 8 })
                  .backgroundColor(this.selectedOperation === op.value ? '#1A237E' : '#E0E0E0')
                  .fontColor(this.selectedOperation === op.value ? '#FFFFFF' : '#333333')
                  .fontSize(12)
                  .onClick(() => {
                    this.selectedOperation = op.value;
                    this.result = '';
                    this.resultTitle = '';
                  })
              })
            }
            .width('100%')
          }
          .width('95%')
          .margin({ top: 16, left: '2.5%', right: '2.5%', bottom: 16 })
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(6)

          // 参数输入
          if (this.selectedOperation === 'int' || this.selectedOperation === 'double' || 
              this.selectedOperation === 'array') {
            Column() {
              Text('输入参数')
                .fontSize(14)
                .fontWeight(FontWeight.Bold)
                .fontColor('#333333')
                .margin({ bottom: 8 })

              TextInput({ placeholder: '最小值', text: this.minValue })
                .onChange((value) => this.minValue = value)
                .width('100%')
                .height(50)
                .padding(12)
                .border({ width: 1, color: '#4DB6AC' })
                .borderRadius(6)
                .fontSize(12)
                .margin({ bottom: 12 })

              TextInput({ placeholder: '最大值', text: this.maxValue })
                .onChange((value) => this.maxValue = value)
                .width('100%')
                .height(50)
                .padding(12)
                .border({ width: 1, color: '#4DB6AC' })
                .borderRadius(6)
                .fontSize(12)
            }
            .width('95%')
            .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
            .padding(12)
            .backgroundColor('#FFFFFF')
            .borderRadius(6)
          }

          // 操作按钮
          Row() {
            Button('✨ 生成')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#1A237E')
              .fontColor('#FFFFFF')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .borderRadius(6)
              .onClick(() => this.executeOperation())

            Blank()
              .width(12)

            Button('🔄 清空')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#F5F5F5')
              .fontColor('#1A237E')
              .fontSize(14)
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
              .onClick(() => {
                this.result = '';
                this.resultTitle = '';
              })
          }
          .width('95%')
          .margin({ left: '2.5%', right: '2.5%', bottom: 16 })

          // 结果显示
          if (this.resultTitle) {
            Column() {
              Text(this.resultTitle)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .fontColor('#FFFFFF')
                .width('100%')
                .padding(12)
                .backgroundColor('#1A237E')
                .borderRadius(6)
                .textAlign(TextAlign.Center)
                .margin({ bottom: 12 })

              Scroll() {
                Text(this.result)
                  .fontSize(12)
                  .fontColor('#333333')
                  .fontFamily('monospace')
                  .textAlign(TextAlign.Start)
                  .width('100%')
                  .padding(12)
                  .selectable(true)
              }
              .width('100%')
              .height(300)
              .backgroundColor('#F9F9F9')
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
            }
            .width('95%')
            .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
            .padding(12)
            .backgroundColor('#FFFFFF')
            .borderRadius(6)
          }
        }
        .width('100%')
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  private executeOperation() {
    try {
      switch (this.selectedOperation) {
        case 'int':
          const min = parseInt(this.minValue) || 0;
          const max = parseInt(this.maxValue) || 100;
          const randomInt = this.randomGenerator.nextInt(min, max);
          this.resultTitle = '🎯 随机整数';
          this.result = `范围: ${min} - ${max}\n结果: ${randomInt}`;
          break;

        case 'double':
          const minD = parseFloat(this.minValue) || 0;
          const maxD = parseFloat(this.maxValue) || 1;
          const randomDouble = this.randomGenerator.nextDouble(minD, maxD);
          this.resultTitle = '🎯 随机浮点数';
          this.result = `范围: ${minD} - ${maxD}\n结果: ${randomDouble.toFixed(4)}`;
          break;

        case 'boolean':
          const randomBool = this.randomGenerator.nextBoolean();
          this.resultTitle = '✅ 随机布尔值';
          this.result = `结果: ${randomBool ? '真' : '假'}`;
          break;

        case 'string':
          const randomStr = this.randomGenerator.nextString(10);
          this.resultTitle = '📝 随机字符串';
          this.result = `长度: 10\n结果: ${randomStr}`;
          break;

        case 'uuid':
          const uuid = this.randomGenerator.nextUUID();
          this.resultTitle = '🆔 随机 UUID';
          this.result = `UUID: ${uuid}`;
          break;

        case 'color':
          const color = this.randomGenerator.nextColor();
          this.resultTitle = '🎨 随机颜色';
          this.result = `颜色: ${color}`;
          break;

        case 'dice':
          const diceResult = this.randomGenerator.rollDice(6, 3);
          this.resultTitle = '🎲 掷骰子结果';
          this.result = `掷 3 个骰子\n结果: ${diceResult.join(', ')}\n总和: ${diceResult.reduce((a, b) => a + b, 0)}`;
          break;

        case 'shuffle':
          const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
          const shuffled = this.randomGenerator.shuffle(list);
          this.resultTitle = '🔀 随机排列';
          this.result = `原列表: ${list.join(', ')}\n排列后: ${shuffled.join(', ')}`;
          break;

        case 'array':
          const size = parseInt(this.minValue) || 5;
          const minA = parseInt(this.maxValue) || 0;
          const maxA = 100;
          const randomArray = this.randomGenerator.nextIntArray(size, minA, maxA);
          this.resultTitle = '📊 随机数组';
          this.result = `大小: ${size}\n范围: ${minA} - ${maxA}\n结果: ${randomArray.join(', ')}`;
          break;
      }
    } catch (e) {
      this.resultTitle = '❌ 生成出错';
      this.result = `错误: ${e}`;
    }
  }
}

ArkTS 集成的关键要点

在 OpenHarmony 应用中集成随机数生成工具库需要考虑多种操作类型和用户体验。我们设计了一个灵活的 UI,能够支持不同的随机数生成操作。

操作选择界面使用了 Flex 布局和 FlexWrap 来实现响应式的按钮排列。当用户选择不同的操作时,输入区域会动态显示相应的输入字段。

对于需要参数的操作(如随机整数、随机浮点数等),我们提供了最小值和最大值的输入框。结果显示使用了可选择的文本,这样用户可以轻松复制生成的随机数。

对于骰子操作,我们同时显示了每个骰子的结果和总和。对于随机排列,我们显示了原列表和排列后的列表进行对比。

工作流程详解

随机数生成的完整流程

  1. 操作选择: 用户在 ArkTS UI 中选择要执行的随机数生成操作
  2. 参数输入: 用户输入必要的参数(如范围、数量等)
  3. 生成执行: 调用 RandomGenerator 的相应方法
  4. 结果展示: 将生成的随机数显示在 UI 中

跨平台一致性

通过 KMP 技术,我们确保了在所有平台上的行为一致性。无论是在 Kotlin/JVM、Kotlin/JS 还是通过 ArkTS 调用,随机数生成的逻辑和结果都是完全相同的。

实际应用场景

游戏开发

在游戏开发中,需要生成随机数用于游戏逻辑、敌人行为、物品掉落等。这个工具库提供了必要的随机数生成功能。

数据模拟

在数据模拟和测试中,需要生成大量的随机数据。这个工具库提供了生成随机数组和随机字符串的功能。

安全加密

在安全加密中,需要生成随机数用于密钥、盐值等。这个工具库提供了 UUID 和随机字符串生成功能。

统计分析

在统计分析中,需要生成随机样本进行分析。这个工具库提供了各种随机数生成功能。

性能优化

缓存随机数

在需要大量随机数时,可以预先生成并缓存随机数以提高性能。

批量生成

在生成大量随机数时,应该考虑使用批量生成的方式以提高效率。

安全性考虑

加密安全的随机数

在安全相关的应用中,应该使用加密安全的随机数生成器而不是普通的随机数生成器。

种子管理

在需要可重现的随机数时,应该妥善管理随机数生成器的种子。

总结

这个 KMP OpenHarmony 随机数生成工具库展示了如何使用现代的跨平台技术来处理常见的随机数生成任务。通过 Kotlin Multiplatform 技术,我们可以在一个地方编写业务逻辑,然后在多个平台上使用。

随机数生成是应用开发中的基础功能。通过使用这样的工具库,开发者可以快速、可靠地处理各种随机数生成操作,从而提高开发效率和代码质量。

在实际应用中,建议根据具体的需求进行定制和扩展,例如添加更多的随机数生成方法、实现加密安全的随机数生成等高级特性。同时,定期进行性能测试和优化,确保应用在生成大量随机数时仍然保持良好的性能。在这里插入图片描述

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐