HarmonyOS开发:A/B测试——实验分析

举报
Jack20 发表于 2026/06/25 20:53:05 2026/06/25
【摘要】 HarmonyOS开发:A/B测试——实验分析📌 核心要点:A/B测试是用数据代替直觉做决策的利器——设计实验、分流用户、收集数据、统计检验,让每个产品决策都有数据支撑,不再靠拍脑袋。 背景与动机产品经理说"新版首页转化率更高",开发说"旧版用户更习惯",老板说"我觉得新版好"。三个人三种意见,听谁的?听数据的。但问题来了——你怎么知道新版首页转化率更高?凭感觉?凭几个用户的反馈?还是凭...

HarmonyOS开发:A/B测试——实验分析

📌 核心要点:A/B测试是用数据代替直觉做决策的利器——设计实验、分流用户、收集数据、统计检验,让每个产品决策都有数据支撑,不再靠拍脑袋。

背景与动机

产品经理说"新版首页转化率更高",开发说"旧版用户更习惯",老板说"我觉得新版好"。

三个人三种意见,听谁的?听数据的。

但问题来了——你怎么知道新版首页转化率更高?凭感觉?凭几个用户的反馈?还是凭你自己的使用体验?

都不是。你得做A/B测试——把用户随机分成两组,一组看旧版,一组看新版,用数据说话。如果新版转化率确实高,就全量切新版。如果没区别甚至更差,就别折腾了。

A/B测试要解决的核心问题:

  • 实验怎么设计:假设是什么?指标是什么?跑多久?
  • 流量怎么分:怎么保证分组公平?样本量够不够?
  • 结果怎么看:差异是真实的还是随机的?统计上显著吗?
  • 决策怎么做:赢了就上,输了就撤,平局怎么办?

鸿蒙应用的A/B测试有其特殊性——分布式场景下用户可能跨设备,分流逻辑需要考虑设备一致性。

核心原理

A/B测试的完整流程:假设提出 → 实验设计 → 流量分配 → 数据采集 → 统计检验 → 决策执行

flowchart TB
    subgraph 设计阶段
        A[提出假设<br/>新首页转化率更高] --> B[定义指标<br/>主指标+辅助指标]
        B --> C[确定样本量<br/>最小可检测效应]
        C --> D[设计实验方案<br/>分组+时长+流量]
    end
    
    subgraph 执行阶段
        D --> E[流量分配<br/>随机+分层]
        E --> F[实验组A<br/>旧版首页]
        E --> G[实验组B<br/>新版首页]
        F --> H[数据采集]
        G --> H
    end
    
    subgraph 分析阶段
        H --> I[统计检验<br/>Z检验/卡方检验]
        I --> J{统计显著?}
        J -->|p<0.05| K[✅ 实验结果可信]
        J -->|p≥0.05| L[❌ 差异不显著<br/>延长实验或放弃]
    end
    
    subgraph 决策阶段
        K --> M{效果方向}
        M -->|实验组胜出| N[全量发布新版]
        M -->|对照组胜出| O[保留旧版]
        M -->|无显著差异| P[综合考虑<br/>成本/体验/技术]
    end
    
    classDef design fill:#6C5CE7,stroke:#5B4BC9,color:#fff
    classDef execute fill:#00B894,stroke:#00A383,color:#fff
    classDef analyze fill:#FDCB6E,stroke:#F0B429,color:#333
    classDef decide fill:#FF7675,stroke:#D63031,color:#fff
    classDef decision fill:#74B9FF,stroke:#0984E3,color:#fff
    classDef success fill:#55EFC4,stroke:#00B894,color:#333
    classDef fail fill:#E17055,stroke:#D63031,color:#fff
    
    class A,B,C,D design
    class E,F,G,H execute
    class I analyze
    class J decision
    class K success
    class L fail
    class M decision
    class N success
    class O fail
    class P decide

A/B测试的关键概念:

概念 说明 典型值
原假设H0 实验组和对照组无差异
备择假设H1 实验组和对照组有差异
显著性水平α 犯第一类错误的概率 0.05
统计功效1-β 正确拒绝H0的概率 0.8
最小可检测效应MDE 能检测到的最小差异 基线×5%
置信区间 真实效应的估计范围 95% CI
p值 观察到当前或更极端结果的概率 <0.05

代码实战

基础用法:实验分流

先把用户分流做好——这是A/B测试的基础。

// ABTestManager.ets - A/B测试管理器
import { preferences } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { analytics } from '@kit.AnalyticsKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 实验定义
export interface Experiment {
  experimentId: string;        // 实验ID
  experimentName: string;      // 实验名称
  variants: Variant[];         // 实验变体
  trafficPercent: number;      // 实验流量占比(0-1)
  isActive: boolean;           // 是否激活
}

// 变体定义
export interface Variant {
  variantId: string;           // 变体ID
  variantName: string;         // 变体名称
  trafficWeight: number;       // 流量权重(0-1)
  isControl: boolean;          // 是否对照组
}

// 分流结果
export interface Assignment {
  experimentId: string;
  variantId: string;
  variantName: string;
  isControl: boolean;
}

export class ABTestManager {
  private static instance: ABTestManager;
  private pref: preferences.Preferences | null = null;
  private experiments: Map<string, Experiment> = new Map();
  private assignments: Map<string, Assignment> = new Map(); // 缓存分流结果
  private userId: string = '';
  
  static getInstance(): ABTestManager {
    if (!ABTestManager.instance) {
      ABTestManager.instance = new ABTestManager();
    }
    return ABTestManager.instance;
  }
  
  async init(context: common.UIAbilityContext): Promise<void> {
    this.pref = await preferences.getPreferences(context, 'ab_test');
    // 加载已保存的分流结果
    await this.loadAssignments();
  }
  
  // 设置用户ID
  setUserId(userId: string): void {
    this.userId = userId;
  }
  
  // 注册实验
  registerExperiment(experiment: Experiment): void {
    this.experiments.set(experiment.experimentId, experiment);
    console.info(`[ABTest] 注册实验: ${experiment.experimentName}`);
  }
  
  // 获取用户分流——核心方法
  async getVariant(experimentId: string): Promise<Assignment> {
    // 1. 检查缓存
    const cacheKey = `${experimentId}_${this.userId}`;
    if (this.assignments.has(cacheKey)) {
      return this.assignments.get(cacheKey)!;
    }
    
    // 2. 检查实验是否存在
    const experiment = this.experiments.get(experimentId);
    if (!experiment || !experiment.isActive) {
      // 实验不存在或未激活,返回默认值
      return this.getDefaultAssignment(experimentId);
    }
    
    // 3. 检查是否在实验流量内
    const userHash = this.hashUserId(this.userId, experimentId);
    if (userHash >= experiment.trafficPercent) {
      // 不在实验流量内
      return this.getDefaultAssignment(experimentId);
    }
    
    // 4. 分流——基于用户ID哈希
    const assignment = this.assignVariant(experiment, userHash);
    
    // 5. 缓存分流结果
    this.assignments.set(cacheKey, assignment);
    await this.saveAssignment(cacheKey, assignment);
    
    // 6. 上报曝光事件
    analytics.reportEvent('ab_exposure', {
      'experiment_id': experimentId,
      'variant_id': assignment.variantId,
      'variant_name': assignment.variantName,
      'is_control': assignment.isControl,
    });
    
    console.info(
      `[ABTest] 分流结果: ${experiment.experimentName}` +
      `${assignment.variantName} (${assignment.isControl ? '对照组' : '实验组'})`
    );
    
    return assignment;
  }
  
  // 分流算法——基于用户ID哈希
  private assignVariant(experiment: Experiment, userHash: number): Assignment {
    // 归一化到0-1范围
    const normalizedHash = userHash / experiment.trafficPercent;
    
    // 按权重分配变体
    let cumulative = 0;
    for (const variant of experiment.variants) {
      cumulative += variant.trafficWeight;
      if (normalizedHash <= cumulative) {
        return {
          experimentId: experiment.experimentId,
          variantId: variant.variantId,
          variantName: variant.variantName,
          isControl: variant.isControl,
        };
      }
    }
    
    // 默认返回最后一个变体
    const lastVariant = experiment.variants[experiment.variants.length - 1];
    return {
      experimentId: experiment.experimentId,
      variantId: lastVariant.variantId,
      variantName: lastVariant.variantName,
      isControl: lastVariant.isControl,
    };
  }
  
  // 用户ID哈希——保证同一用户始终分到同一组
  private hashUserId(userId: string, experimentId: string): number {
    const str = `${userId}_${experimentId}`;
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // 转为32位整数
    }
    return Math.abs(hash) % 10000 / 10000; // 归一化到0-1
  }
  
  // 获取默认分配
  private getDefaultAssignment(experimentId: string): Assignment {
    return {
      experimentId: experimentId,
      variantId: 'default',
      variantName: '默认',
      isControl: true,
    };
  }
  
  // 保存分流结果
  private async saveAssignment(key: string, assignment: Assignment): Promise<void> {
    if (!this.pref) return;
    await this.pref.put(key, JSON.stringify(assignment));
    await this.pref.flush();
  }
  
  // 加载已保存的分流结果
  private async loadAssignments(): Promise<void> {
    if (!this.pref) return;
    // 加载所有缓存的分流结果
    const allKeys = await this.pref.getAll();
    for (const [key, value] of Object.entries(allKeys)) {
      if (key.includes('_')) {
        this.assignments.set(key, JSON.parse(value as string));
      }
    }
  }
}

进阶用法:统计显著性检验

实验跑完了,数据有了,但差异是真实的还是随机的?得做统计检验。

// ABTestStatistics.ets - A/B测试统计检验
import { analytics } from '@kit.AnalyticsKit';

// 实验数据
export interface ExperimentData {
  variantId: string;
  sampleSize: number;           // 样本量
  conversions: number;          // 转化数
  conversionRate: number;       // 转化率
  metricValue: number;          // 指标值(用于连续指标)
  metricStdDev: number;         // 标准差(用于连续指标)
}

// 检验结果
export interface TestResult {
  isSignificant: boolean;       // 是否统计显著
  pValue: number;              // p值
  confidenceLevel: number;     // 置信度
  effectSize: number;          // 效应量
  relativeImprovement: number;  // 相对提升
  confidenceInterval: {         // 置信区间
    lower: number;
    upper: number;
  };
  recommendation: string;      // 建议
}

export class ABTestStatistics {
  private static instance: ABTestStatistics;
  
  static getInstance(): ABTestStatistics {
    if (!ABTestStatistics.instance) {
      ABTestStatistics.instance = new ABTestStatistics();
    }
    return ABTestStatistics.instance;
  }
  
  // 比例检验(转化率类指标)
  testProportion(control: ExperimentData, treatment: ExperimentData): TestResult {
    const n1 = control.sampleSize;
    const n2 = treatment.sampleSize;
    const p1 = control.conversionRate;
    const p2 = treatment.conversionRate;
    
    // 合并比例
    const pPool = (control.conversions + treatment.conversions) / (n1 + n2);
    
    // 标准误差
    const se = Math.sqrt(pPool * (1 - pPool) * (1 / n1 + 1 / n2));
    
    // Z统计量
    const z = se > 0 ? (p2 - p1) / se : 0;
    
    // p值(双尾检验)
    const pValue = 2 * (1 - this.normalCDF(Math.abs(z)));
    
    // 效应量
    const effectSize = p2 - p1;
    
    // 相对提升
    const relativeImprovement = p1 > 0 ? (p2 - p1) / p1 : 0;
    
    // 95%置信区间
    const seDiff = Math.sqrt(p1 * (1 - p1) / n1 + p2 * (1 - p2) / n2);
    const zCritical = 1.96; // 95%置信度
    const ciLower = effectSize - zCritical * seDiff;
    const ciUpper = effectSize + zCritical * seDiff;
    
    const isSignificant = pValue < 0.05;
    
    return {
      isSignificant: isSignificant,
      pValue: Math.round(pValue * 10000) / 10000,
      confidenceLevel: Math.round((1 - pValue) * 10000) / 100,
      effectSize: Math.round(effectSize * 10000) / 100,
      relativeImprovement: Math.round(relativeImprovement * 10000) / 100,
      confidenceInterval: {
        lower: Math.round(ciLower * 10000) / 100,
        upper: Math.round(ciUpper * 10000) / 100,
      },
      recommendation: this.getRecommendation(isSignificant, relativeImprovement, pValue),
    };
  }
  
  // 计算所需样本量
  calculateSampleSize(
    baselineRate: number,       // 基线转化率
    mde: number,                // 最小可检测效应(相对变化)
    alpha: number = 0.05,       // 显著性水平
    power: number = 0.8         // 统计功效
  ): number {
    const p1 = baselineRate;
    const p2 = baselineRate * (1 + mde);
    const pAvg = (p1 + p2) / 2;
    
    // Z值
    const zAlpha = this.inverseNormalCDF(1 - alpha / 2);
    const zBeta = this.inverseNormalCDF(power);
    
    // 样本量公式
    const n = (
      zAlpha * Math.sqrt(2 * pAvg * (1 - pAvg)) +
      zBeta * Math.sqrt(p1 * (1 - p1) + p2 * (1 - p2))
    ) ** 2 / (p2 - p1) ** 2;
    
    return Math.ceil(n);
  }
  
  // 生成建议
  private getRecommendation(
    isSignificant: boolean, 
    improvement: number, 
    pValue: number
  ): string {
    if (!isSignificant) {
      if (pValue > 0.3) {
        return '差异不显著且p值较大,建议停止实验,保留原方案。';
      }
      return '差异不显著,建议延长实验周期或增加样本量。';
    }
    
    if (improvement > 0) {
      return `实验组转化率显著提升${Math.round(improvement * 100)}%,建议全量发布。`;
    } else {
      return `实验组转化率显著下降${Math.round(Math.abs(improvement) * 100)}%,建议保留原方案。`;
    }
  }
  
  // 标准正态分布CDF(近似)
  private normalCDF(z: number): number {
    // 使用近似公式
    const a1 = 0.254829592;
    const a2 = -0.284496736;
    const a3 = 1.421413741;
    const a4 = -1.453152027;
    const a5 = 1.061405429;
    const p = 0.3275911;
    
    const sign = z < 0 ? -1 : 1;
    z = Math.abs(z) / Math.sqrt(2);
    
    const t = 1.0 / (1.0 + p * z);
    const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-z * z);
    
    return 0.5 * (1.0 + sign * y);
  }
  
  // 逆标准正态分布CDF(近似)
  private inverseNormalCDF(p: number): number {
    // 简单近似
    if (p === 0.95) return 1.645;
    if (p === 0.975) return 1.96;
    if (p === 0.8) return 0.842;
    if (p === 0.9) return 1.282;
    
    // 更通用的近似
    const a = -3.969683028665376e+01;
    const b = 2.209460984245205e+02;
    const c = -2.759285104469687e+02;
    const d = 1.383577518672690e+02;
    const e = -3.066479806614716e+01;
    const f = 2.506628277459239e+00;
    
    const pLow = 0.02425;
    const pHigh = 1 - pLow;
    
    let q, r;
    
    if (p < pLow) {
      q = Math.sqrt(-2 * Math.log(p));
      return (((((c * q + d) * q + e) * q + f) * q + a) * q + b) * q;
    } else if (p <= pHigh) {
      q = p - 0.5;
      r = q * q;
      return q * (((((a * r + b) * r + c) * r + d) * r + e) * r + f) / 
             ((((a * r + b) * r + c) * r + d) * r + 1);
    } else {
      q = Math.sqrt(-2 * Math.log(1 - p));
      return -(((((c * q + d) * q + e) * q + f) * q + a) * q + b) * q;
    }
  }
}

完整示例:首页改版A/B测试

一个完整的首页改版A/B测试,从实验设计到决策执行。

// HomeABTest.ets - 首页改版A/B测试
import { ABTestManager, Experiment, Assignment } from './ABTestManager';
import { ABTestStatistics, ExperimentData, TestResult } from './ABTestStatistics';
import { analytics } from '@kit.AnalyticsKit';
import { common } from '@kit.AbilityKit';

// 首页版本
export enum HomeVariant {
  CONTROL = 'home_v1',         // 旧版首页
  TREATMENT = 'home_v2',       // 新版首页
}

// 首页实验定义
const HOME_EXPERIMENT: Experiment = {
  experimentId: 'home_redesign_2024',
  experimentName: '首页改版实验',
  trafficPercent: 0.5,   // 50%流量参与实验
  isActive: true,
  variants: [
    {
      variantId: HomeVariant.CONTROL,
      variantName: '旧版首页',
      trafficWeight: 0.5,   // 50%流量
      isControl: true,
    },
    {
      variantId: HomeVariant.TREATMENT,
      variantName: '新版首页',
      trafficWeight: 0.5,   // 50%流量
      isControl: false,
    },
  ],
};

export class HomeABTest {
  private static instance: HomeABTest;
  private abManager: ABTestManager;
  private statistics: ABTestStatistics;
  private currentVariant: HomeVariant = HomeVariant.CONTROL;
  
  // 实验数据收集
  private controlData: ExperimentData = {
    variantId: HomeVariant.CONTROL,
    sampleSize: 0,
    conversions: 0,
    conversionRate: 0,
    metricValue: 0,
    metricStdDev: 0,
  };
  
  private treatmentData: ExperimentData = {
    variantId: HomeVariant.TREATMENT,
    sampleSize: 0,
    conversions: 0,
    conversionRate: 0,
    metricValue: 0,
    metricStdDev: 0,
  };
  
  static getInstance(): HomeABTest {
    if (!HomeABTest.instance) {
      HomeABTest.instance = new HomeABTest();
    }
    return HomeABTest.instance;
  }
  
  constructor() {
    this.abManager = ABTestManager.getInstance();
    this.statistics = ABTestStatistics.getInstance();
  }
  
  // 初始化实验
  async init(context: common.UIAbilityContext): Promise<void> {
    await this.abManager.init(context);
    
    // 注册实验
    this.abManager.registerExperiment(HOME_EXPERIMENT);
    
    // 获取分流结果
    const assignment = await this.abManager.getVariant(HOME_EXPERIMENT.experimentId);
    this.currentVariant = assignment.variantId as HomeVariant;
    
    console.info(`[HomeABTest] 当前版本: ${assignment.variantName}`);
  }
  
  // 获取当前首页版本
  getVariant(): HomeVariant {
    return this.currentVariant;
  }
  
  // 记录首页曝光
  recordExposure(): void {
    if (this.currentVariant === HomeVariant.CONTROL) {
      this.controlData.sampleSize++;
    } else {
      this.treatmentData.sampleSize++;
    }
  }
  
  // 记录转化(如:点击商品、加入购物车)
  recordConversion(): void {
    if (this.currentVariant === HomeVariant.CONTROL) {
      this.controlData.conversions++;
      this.controlData.conversionRate = 
        this.controlData.conversions / this.controlData.sampleSize;
    } else {
      this.treatmentData.conversions++;
      this.treatmentData.conversionRate = 
        this.treatmentData.conversions / this.treatmentData.sampleSize;
    }
    
    // 上报转化事件
    analytics.reportEvent('home_conversion', {
      'variant': this.currentVariant,
      'is_control': this.currentVariant === HomeVariant.CONTROL,
    });
  }
  
  // 分析实验结果
  analyzeResult(): TestResult {
    const result = this.statistics.testProportion(
      this.controlData,
      this.treatmentData
    );
    
    console.info('\n========== A/B测试结果 ==========');
    console.info(`对照组: ${this.controlData.sampleSize}人, ` +
      `转化率${(this.controlData.conversionRate * 100).toFixed(2)}%`);
    console.info(`实验组: ${this.treatmentData.sampleSize}人, ` +
      `转化率${(this.treatmentData.conversionRate * 100).toFixed(2)}%`);
    console.info(`p值: ${result.pValue}`);
    console.info(`统计显著: ${result.isSignificant ? '是' : '否'}`);
    console.info(`相对提升: ${result.relativeImprovement}%`);
    console.info(`建议: ${result.recommendation}`);
    console.info('====================================\n');
    
    // 上报实验结果
    analytics.reportEvent('ab_test_result', {
      'experiment_id': HOME_EXPERIMENT.experimentId,
      'control_rate': this.controlData.conversionRate,
      'treatment_rate': this.treatmentData.conversionRate,
      'p_value': result.pValue,
      'is_significant': result.isSignificant,
      'relative_improvement': result.relativeImprovement,
    });
    
    return result;
  }
  
  // 计算所需样本量
  getRequiredSampleSize(): number {
    // 假设基线转化率5%,期望提升10%
    return this.statistics.calculateSampleSize(0.05, 0.10);
  }
}

在首页中使用A/B测试:

// HomePage.ets
import { HomeABTest, HomeVariant } from '../abtest/HomeABTest';

@Entry
@Component
struct HomePage {
  private abTest = HomeABTest.getInstance();
  @State variant: HomeVariant = HomeVariant.CONTROL;
  
  async aboutToAppear() {
    this.variant = this.abTest.getVariant();
    this.abTest.recordExposure();
  }
  
  build() {
    Column() {
      if (this.variant === HomeVariant.CONTROL) {
        this.OldHome()
      } else {
        this.NewHome()
      }
    }
    .width('100%')
    .height('100%')
  }
  
  @Builder OldHome() {
    // 旧版首页:列表布局
    Column() {
      Text('旧版首页')
      List() {
        // 商品列表...
      }
    }
  }
  
  @Builder NewHome() {
    // 新版首页:卡片布局+推荐
    Column() {
      Text('新版首页')
      // 推荐区域
      Scroll() {
        // 推荐卡片...
      }
    }
  }
}

踩坑与注意事项

1. 样本量不够别下结论

100个用户,实验组转化率8%,对照组5%,看起来实验组赢了?别急着下结论——样本量太小,差异可能只是随机波动。先算一下所需样本量,等样本量够了再看结果。

2. 别偷看实验结果

实验跑了一周,你忍不住看了一眼数据——实验组领先!于是你停止实验,全量发布。这是A/B测试的大忌。提前停止实验会导致假阳性——你看到的差异可能只是随机波动。实验周期必须提前确定,跑满再分析。

3. 分流要一致

同一个用户今天看到新版,明天看到旧版?那用户体验就乱了。分流结果必须持久化——一旦用户被分到某个组,整个实验期间都保持不变。

4. 一次只测一个变量

新版首页改了布局、改了配色、改了推荐算法——三个变量一起改,你怎么知道哪个变量有效?一次只改一个变量,其他保持不变,这样才能准确归因。

5. 注意新奇效应

新版上线初期,用户可能因为新鲜感而表现更好,这叫新奇效应。等新鲜感过了,数据可能就回落了。所以实验至少跑2周,等新奇效应消退后再看结果。

HarmonyOS 6适配说明

HarmonyOS 6在A/B测试方面的更新:

  1. 服务端分流:新增analytics.getExperimentVariant()接口,服务端统一分流,客户端无需维护分流逻辑
  2. 跨设备一致性:基于华为账号的分流,用户在不同设备上看到相同的实验版本
  3. 自动统计检验:实验数据自动进行统计检验,开发者无需手动计算
  4. 实验看板:DevEco Studio集成实验看板,实时查看实验进度和结果
// HarmonyOS 6 服务端分流
async function getServerVariant(experimentId: string): Promise<string> {
  try {
    const result = await analytics.getExperimentVariant({
      experimentId: experimentId,
    });
    console.info(`[ABTest] 服务端分流: ${result.variantId}`);
    return result.variantId;
  } catch (error) {
    console.error('[ABTest] 服务端分流失败,使用本地分流');
    return 'default';
  }
}

总结

A/B测试是用数据代替直觉做决策的利器——没有A/B测试,产品决策就是拍脑袋。设计好实验、保证分流公平、跑够样本量、做统计检验,这是A/B测试的基本功。

维度 评价
学习难度 ⭐⭐⭐⭐☆ 分流简单,统计检验需要数学基础
使用频率 ⭐⭐⭐⭐☆ 每次重大功能变更都需要
重要程度 ⭐⭐⭐⭐⭐ 直接影响产品决策质量

核心记住三点:样本量不够别下结论、一次只测一个变量、实验周期必须提前确定。A/B测试不是万能的——它只能告诉你A和B哪个更好,不能告诉你C会不会更好。但在A和B之间做选择时,数据永远比直觉可靠。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。