【F#入门】第五讲 模式匹配

F#语言的软件工程 F#是由微软开发的一种多范式编程语言,主要用于.NET平台。它结合了功能性编程、面向对象编程以及命令式编程的优点,允许开发者用更少的代码实现复杂的功能。F#可以和C#等其他.NET语言无缝集成,利于现有项目的迁移和改进。 阅读详情

上一期中,我们学习了函数,以及数据是如何在管道中流动的。

在这一其中,我们将学习如何分解我的数据,用各种方式判断或者获取其中的信息。便是我们今天要学习的内容,模式匹配。

模式是转换输入数据的规则,在F#中,我们有非常多的模式支持,以供我们使用,本期内容我们就来介绍一下这些模式。以及一些模式匹配令人震惊的案例

名字

描述

例

常量模式

任何数值、字符或字符串文本、枚举常量或定义的文本标识符

1.0

、"test"、30、Color.Red

标识符模式

可区分联合、异常标签或活动模式用例的 case 值

Some(x)



Failure(msg)

变量模式

identifiera
as

模式

pattern

asidentifier

(a, b) as tuple1

OR 模式

pattern1

|pattern2

([h] | [h; _])

AND 模式

pattern1

&pattern2

(a, b) & (_, "test")

Cons 模式

标识符

::列表标识符

h :: t

列表模式

[ pattern_1; ... ; pattern_n]

[ a; b; c ]

数组模式

[| pattern_1; ..; pattern_n|]

[| a; b; c |]

带括号模式

( pattern)

( a )

元组模式

( pattern_1, ... , pattern_n)

( a, b )

记录模式

{identifier1=pattern_1; ... ;identifier_n=pattern_n}

{ Name = name; }

通配符模式

_

_

模式和类型注释

pattern

:type

a : int

类型测试模式

:?type[ asidentifier]

:? System.DateTime as dt

Null 模式

零

null

Nameof 模式

nameof exprnameof str

模式匹配使业务规则更清晰可见,代码更接近问题域的表述

模式匹配是递归算法的自然表达方式,这在函数式编程中尤为重要

以下match with之间采用多采用直接使用字面量的方式直接使用,实际中当然可以使用变量来输入

常量模式 OR/And模式 _模式

// 常量模式
[<Literal>]
let Three = 3
let res = 
    match 2 with
    | 1 | 2 -> "one or two" // OR模式 / AND模式
    | Three -> "three"
    | _ -> "other" // 弃元模式
printfn "%A" res

常量模式可以直接使用例如 1, 2等字面量,也可以使用带有Literal特性(否则会变为变量模式)的常量.用于匹配特定值的情况

OR/AND模式, 通过| 和 &来表示模式的条件, 1 | 2表示的就是1或者2时都可以成功匹配

_模式, 与C#弃元模式一样,用于匹配剩余所有情况

变量模式

let res1 = 
    match 5 with
    // | x -> x + 1 // 变量模式
    | x when x < 5 -> x + 1 // 变量模式
    | _ -> 0

用于捕获符合条件的变量, 通过when来限定条件, 例如代码中 当输入小于5时,才会被该模式匹配

标识符模式

let sData = Some 1
let res2 = 
    match sData with
    | Some x when x < 5 -> x + 1 // 变量模式
    | None -> 1
    | _ -> 0 // 弃元模式
printfn "%A" res2

在之前的内容中我们已经见过他好多次了, 在函数式编程中我们经常会用到他, 用于匹配形如可区分联合的值(本例中匹配Option的Some 与None)

元组模式

let tupleA = (2, 2)
let res3 = 
    match tupleA with
    | (1, x)  -> x + 1 // 变量模式
    | (_, x)  -> x - 1 // 变量模式
    | _ -> 0 // 弃元模式
printfn "%A" res3

用于匹配元组中的多个元素,可与变量模式, 标识符模式等其他模式一起使用

Cons模式

// Cons模式
let listA = [1; 2; 3]
let res4 = 
    match listA with
    | [] -> 0 // 空列表模式
    | head::tail -> head // Cons模式
printfn "%A" res4

Cons模式用于处理列表的两部分, head代表第一个元素, tail代表剩下的所有元素,同样的,这个模式在函数式编程中,和递归中非常常见.

列表模式, 数组模式

// 列表模式/数组模式
let listB = [1; 2; 3]
let res5 = 
    match listB with
    | [1; 2] -> 0 // 列表模式
    | [1; v; 3] -> v // 列表模式
    | _ -> 0 // 弃元模式
let arrayA = [|1; 2; 3|]
let res6 = 
    match arrayA with
    | [|1; 2|] -> 0 // 数组模式
    | [|1; v; 3|] -> v // 数组模式
    | _ -> 0 // 弃元模式

与C#的列表模式类似,不过功能上稍弱,  用于匹配列表/数组的元素模式, 也可以和其他模式混合使用

记录模式

type RecordA = 
    {
        X: int
        Z: int
        Y: RecordA option
    }
let recordA = {X = 1; Z = 2; Y = None}
let res7 = 
    match recordA with
    | {X = 1; Y = Some {X = 1} } -> 1 // 记录模式
    | {Z = 1 } -> 2 // 记录模式
    | _ -> 0 // 弃元模式
printfn "%A" res7

用于匹配记录数据特征的模式匹配,由于函数式编程偏向纯粹的数据表达,该模式也会有这很强大的作用, 例子中第一个模式表达的就是当记录X为1, 并且Y是有值的Record且X也为1, 则进入该模式.

类型模式

match box 1 with
| :? int as i -> printfn "int %d" i
| :? string as s -> printfn "string %s" s

比较偏向oop的模式, 仅了解即可, 与C#的类型模式类似

活动模式

let (|Even|Odd|) aa = if aa % 2 = 0 then Even aa else Odd aa
let res8 = 
    match 1 with
    | Even x -> x + 1 
    | Odd x -> x - 1 
    | _ -> 0 // 弃元模式

let (|RGB|) (color: System.Drawing.Color) = 
    (color.R, color.G, color.B)

    
let (|RGB|HSB|) (color: System.Drawing.Color) = 
    if true then RGB (color.R, color.G, color.B)
    else HSB (color.A, color.B, color.G)

let ChooseColor color = 
    match color with
    | RGB (r, g, b) -> printfn "RGB %d %d %d" r g b 
    | HSB (h, s, b) -> printfn "HSB %d %d %d" h s b 

较为复杂的一种模式使用, 文档甚至为此单开了一页

有点类似于动态的生成了可区分联合,在第一行中,我们可以将输入值,明确的区分为Even或者Odd, 后续可以通过标识符模式正常使用

后两种使用方法,可以将数据在match中直接匹配为我们所需要的形式.

还有一些更为复杂的参数化活动模式等,较为复杂,意义不是特别大,这里就不做详细介绍了,有兴趣也可以参考微软文档介绍。活动模式 - F# | Microsoft Learn

一个有趣的模式匹配运用

最后,我们来看一个模式匹配的较为复杂运用,红黑树的实现

/// 红黑树的颜色
type Color = 
    | Red
    | Black
/// 红黑树节点结构
type RBTree<'T when 'T : comparison> =
    | Empty                                             // 空树
    | Node of Color * RBTree<'T> * 'T * RBTree<'T>      // 颜色, 左子树, 值, 右子树
/// 平衡红黑树
/// 通过模式匹配处理四种不平衡的情况
let balance = function
    | Black, Node(Red, Node(Red, a, x, b), y, c), z, d  // 情况1: 左-左红色节点
    | Black, Node(Red, a, x, Node(Red, b, y, c)), z, d  // 情况2: 左-右红色节点
    | Black, a, x, Node(Red, Node(Red, b, y, c), z, d)  // 情况3: 右-左红色节点
    | Black, a, x, Node(Red, b, y, Node(Red, c, z, d)) -> // 情况4: 右-右红色节点
        Node(Red, Node(Black, a, x, b), y, Node(Black, c, z, d))
    | color, l, v, r -> Node(color, l, v, r)  // 不需要平衡的情况
/// 向红黑树中插入值
let rec insert value tree =
    // 内部插入函数
    let rec ins = function
        | Empty -> Node(Red, Empty, value, Empty)  // 插入到空节点,创建红色节点
        | Node(color, left, v, right) as node ->
            if value < v then 
                // 插入到左子树
                balance(color, ins left, v, right)
            elif value > v then 
                // 插入到右子树
                balance(color, left, v, ins right)
            else 
                // 值已存在,返回原节点
                node
    
    // 确保根节点为黑色
    match ins tree with
    | Node(_, left, v, right) -> Node(Black, left, v, right)
    | Empty -> Empty  // 插入后不应该为空,这种情况实际不会发生
/// 创建空树
let empty = Empty
// 随便插入一些值
let tree = 
    empty
    |> insert 5
    |> insert 3
    |> insert 7
    |> insert 1
    |> insert 4
    |> insert 6
    |> insert 8
    |> insert 2
    |> insert 9
    |> insert 0
    |> insert 10
    |> insert 11
    |> insert 12
let printTree tree =
    // Generated by Copilot
    let rec printNode prefix isLeft node =
        match node with
        | Empty -> printfn "%s--(empty)" prefix
        | Node(color, left, value, right) ->
            // 为节点颜色选择标记
            let colorMark = match color with
                            | Red -> "R"
                            | Black -> "B"
            
            // 打印当前节点值
            printfn "%s%s(%s)%A" prefix (if isLeft then "L--" else "R--") colorMark value
            
            // 计算子节点的缩进前缀
            let childPrefix = prefix + (if isLeft then "|   " else "    ")
            
            // 递归打印左右子树
            printNode childPrefix true left
            printNode childPrefix false right
    
    match tree with
    | Empty -> printfn "(empty tree)"
    | Node(color, left, value, right) ->
        // 为根节点颜色选择标记
        let colorMark = match color with
                        | Red -> "R"
                        | Black -> "B"
        
        // 打印根节点
        printfn "Root(%s)%A" colorMark value
        
        // 打印左右子树
        printNode "  " true left
        printNode "  " false right
// 测试打印函数
printTree tree

如果正常使用命令式的方式编写红黑树,我们可能需要较为复杂的状态判断,以及平衡调整等, 但如果我们使用函数式编程,并使用模式匹配去实现这一点,在刚开始接触时或许会看的有点云里雾里,  不过当我们了解模式匹配的本质后, 这段代码实际上非常清晰明了(虽然效率可能并不特别理想,但这是一种非常有趣的实现方式).

以一种模式作为例子

| Black, Node(Red, Node(Red, a, x, b), y, c), z, d 

我们再看到node的定义 

Node(color, left, value, right)

可以发现,这个模式代表着节点颜色为黑, 且左子树的节点颜色为红,且左子树的左子树节点颜色为红, 当满足这个条件时,就会进入这个模式. 其他部分的字母则是捕获的变量. 

这么一看,是不是逻辑其实非常的清晰呢?

其他的模式也都是一样的道理, 你能写出其代表的意义吗?

当然,如果变量名称写的更具体,可能会使其更具可读性. 模式匹配可以轻松的判断数据的特征, 状态,以及使用这些数据, 而不用去关心无聊的边界问题. 这些复杂繁琐的事情我们丢给编译器帮我们完成. 这是一种更高级的表述模式, 也意味着编译器可以对我们的代码进行更多的优化. 

模式匹配不止在函数式编程中非常有用, 利用好模式匹配, 能够获得非常简洁漂亮的代码!

Bilibili: @无聊的年 【F#入门】(五)模式匹配_哔哩哔哩_bilibili

微信公众号:@scixing的炼丹炉

解析AI人工智能领域AI芯片的散热技术 当你用ChatGPT写代码、用AI生成高清图片时,背后的AI芯片可能正在“发高烧”——全球TOP500超算的平均功耗已突破10兆瓦,单颗GPU的峰值功耗超过700W(相当于3台家用空调同时运行)。本文将聚焦AI芯片的散热技术,覆盖从基础原理到前沿方案的全链条解析,帮助读者理解“散热为什么比算力更重要”。 阅读详情

相关推荐

PCB布线避坑指南:晶振布局的5个致命错误(附正确示例图)

本文深入解析PCB布线中晶振布局的5个致命错误,包括底层布线、电容布局、地平面处理等关键问题,并提供实战解决方案。通过真实案例和量化数据,帮助硬件开发者避免常见陷阱,提升电路稳定性和性能。特别针对晶振这一高敏感元件,给出布线参数黄金法则和三维避让原则。

weixin_29215391的博客 428

Python的模式匹配

一、用法:import re match(pattern,string,flags=0) 第一个参数是正则表达式,如果匹配成功,则返回一个Match,否则返回一个None; 第二个参数表示待匹配的字符串; 第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写等。 二、例子 match = re.match('Hello[\t]*(.*)wor

deqingguo的专栏 8768

GitHub与GitLab中的Fork操作:从个人仓库到团队协作的完整指南

本文详细介绍了GitHub与GitLab中的Fork操作,从个人仓库到团队协作的完整指南。通过Fork操作,开发者可以在权限隔离的环境下自由实验,并通过合并请求机制保证代码质量。文章涵盖了Fork的具体步骤、本地开发环境配置、代码同步方法以及高级协作技巧,帮助团队高效管理代码仓库。

weixin_28829325的博客 306

无涯教程-F# - 模式匹配

从概念上讲,它就像一系列语句。在高级方面,模式匹配遵循F#中的此语法-match exprwithpat1result1pat2->result2pat3whenexpr2->result3->以下示例使用模式匹配语法计算斐波那契数-letrec fib nmatch nwith0->01->1->fibn1fibn2fori1to10doprintfnifib i。

无涯教程 1028

手搓ZLMediaKit实现拉流推流系列3(RK3588上YOLO系列拉流、MPP解码+编码、推流全流程)

 前段时间比较忙,一直没有时间补充后续的内容。今天终于抽出空来,立马进入码字环节:手搓ZLMediaKit实现拉流推流系列在本篇也终于迎来了完结篇,在本篇文章中,你将看到以下一整套完整流程:使用ZLMediaKit拉流---MPP解码---Yolo模型进行推理---MPP编码并推流。

m0_46303486的博客 2175

关于动态存储器dram中rank,bank,device之间的关系

DEVICE_WIDTH表示设备的带宽(单位bit),每个列(column)包含DEVICE_WIDTH 位(bit),每一行(row)包含NUM_COLS个column。   而每一个bank包含NUM_ROWS个行(row)。所以一个设备(device)的存储容量为PER_DEVICE_STORAGE =NUM_ROWS*NUM_COLS*DEVICE_WIDTH*NUM_BANKS (i

wyj7260的专栏 4733

F#语言的语法糖

语法糖(Syntactic Sugar)是指那些在编程语言中提供的更简洁的语法形式,能够使得程序员的代码更加易读、易写,但不改变程序的实质功能。也就是说,语法糖是对某些复杂语法的简化,增强了语言的表达能力。在F#中,语法糖体现在多个方面,包括函数定义、模式匹配、列表和集合操作等,这些糖衣语法极大地提升了代码的可读性和可维护性。F#中的函数定义是其语法糖最明显的特征之一。fsharp这里,let关键字被用来定义一个名为add的函数,它接受两个参数x和y。

2501_90231546的博客 1331

苍穹外卖项目面试总结话术

美食速递这个项目最初是我参与制作的大创项目,是一款为中南学生提供校园外卖送至宿舍服务的软件,包含系统管理后台和小程序端两部分。其中系统管理后台主要提供给食堂内部员工使用,可以对食堂各个窗口、员工、订单、菜品等进行维护管理;小程序端可以在线浏览菜品、添加购物车、下单等,由学生兼职做跑腿送餐上门服务。这是个前后端分离的项目,我主要是负责后端的用户登录、员工管理,菜品管理,订单管理模块的编码实现。

qq_45195447的博客 1万+

【F#入门】第四讲 函数,管道与组合

介绍函数 组合 管道 以及递归函数的概念

scixing的博客 914

西南科技大学模拟电子技术实验二(二极管特性测试及其应用电路)预习报告

3、用二极管正向虚拟IV仪测出数据,并记录数据于虚表3和虚表4。1、按照指导书multisim仿真软件上画出三种模型电路图,1、按照指导书multisim仿真软件上画出三种模型电路图,1、按照指导书multisim仿真软件上画出三种模型电路图,表6 二极管三种模型参数测试表(电源电压=1.2V)2、用万用表测出数据,并记录数据于虚表1和虚表2。2、用万用表测出数据,并记录数据于虚表5和虚表6。表5 二极管三种模型参数测试表(电源电压=12V)二极管三种模型参数测试表(电源电压=12V)

Welcome To My6n Blog 4082

YOLOv11模型压缩技术全面对比:剪枝、量化、蒸馏的原理与实战

YOLOv11模型压缩技术综述 模型压缩技术是解决计算资源受限环境下部署深度学习模型的关键。本文系统介绍了YOLOv11模型压缩的三种核心技术:剪枝、量化和蒸馏。剪枝技术通过移除冗余参数实现模型轻量化,包括结构化剪枝(通道/卷积核剪枝)和非结构化剪枝;量化技术通过降低数值精度(如FP32→INT8)减少存储和计算量;蒸馏技术则利用教师模型指导学生模型训练,在保持精度的同时减小模型规模。三种技术可单独或组合使用,在工业质检、智慧安防等边缘计算场景中发挥重要作用,使YOLOv11在保持80%精度的同时减少70%

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 580

F#程序设计-函数式编程之模式匹配

模式匹配所有程序都需要通过筛选和排序数据;在函数编程中做这些需要用到模式匹配。模式匹配有点像C#和C++中的switch,但是它比switch更强大。模式匹配就是根据输入的数据匹配定义好的一系列规则,如果匹配成功,则执行。该模式匹配表达式然后返回认为是符合规则的结果,因此,在模式匹配的所有规则必须返回相同的类型。如果要执行模式匹配,你可以使用match和with关键字,并在在wit

AAAA的专栏 1918

[VT虚拟化驱动]正式启动VT

文章目录前言一、vmlaunch正式开始虚拟化二、使用步骤1.引入库2.读入数据总结 前言 本章开始真正实现一个最简单的VT框架,当然,只是能跑起来一个VT驱动了,没有并包括EPT,EPT后面再讲 提示:以下是本篇文章正文内容,下面案例可供参考 一、vmlaunch正式开始虚拟化 执行VMLAUNCH指令执行后,就正式进入虚拟化了,再该指令执行之前,得先保存Guest当前的环境,执行完VMLAUNCH后,要恢复Guest的环境,让Guest就像什么都没发生一样,所以需要保存和恢复Guest的各种寄存器的值

吾无法无天的博客 3663

F#学习笔记(五) 模式匹配和递归

这次要说的是F#中的模式匹配,什么是模式匹配,这就相当于C#中的switch语句。根据参数的不同得到不同的结果,如 let patMatch x = match x with | 0 -> printfn "Value is 0" | 1 -> printfn "Value is 1" | _ -> printfn "Value...

aowangue83080的博客 223

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

F#入门-目录

F#入门-目录

LuLingNiu的专栏 805

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

F#语言入门之什么是F#语言

F#是一种函数式编程语言,可以轻松编写正确且可维护的代码。 F#编程主要涉及定义类型推断和自动泛化的类型和函数。 这使您可以将焦点保留在问题域上并操纵其数据,而不是编程的细节。 open System // Gets access to functionality in System namespace. // Defines a function that takes a name an...

u012525929的博客 9840

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

F#奇妙游(21):为什么老是你,模式匹配!

模式匹配是一种编程语言的特性,它可以让我们根据不同的模式来执行不同的代码。模式匹配的本质是一种条件分支,但是它的语法更加简洁,更加清晰。在中,把模式匹配(控制结构)作为F#函数式编程的四个关键概念之一。F#的官方文档中对模式匹配描述为:模式是转换输入数据的规则。可在 F# 中使用模式将数据与一个或多个逻辑结构进行比较,将数据分解为各个构成部分,或通过各种方式从数据中提取信息。

withstand的博客 155

F#语言的学习路线

F#是一种多范式编程语言,支持函数式编程、面向对象编程和命令式编程。作为一种静态类型语言,F#在编译时会进行类型检查,从而提高代码的安全性和可靠性。使用let关键字定义函数。fsharp学习F#是一段充实而又富有挑战性的旅程。通过本文提供的学习路线,从基础知识到进阶技巧,再到项目实践,相信你能够逐步掌握F#编程语言。希望你在F#学习的过程中,能够体验到功能性编程的魅力,并将其运用到实际的开发中。祝你学习顺利!

2501_90443656的博客 2052

F#入门学习(八)

在程序设计中,经常需要检查某值是否在一个范围内,这个范围我们称为模式,比对的过程叫模式匹配。用我们之前学的表达式可以完成,这里用一种更方便的表达式 match表达式 match 测试表达式 with | 模式1 [when条件] ->结果表达式1 | 模式2 [when条件] ->结果表达式2 |… 必须包含所有情况,否则报错,最后可以用_来表示剩下的所有情况。 直接上代码体会。 ...

I_AM_KK的博客 382

F#语言的数据类型

F#允许开发者创建自定义的数据类型以适应复杂的业务逻辑。用户定义的类型可以使用type关键字,可以根据需求结合多种数据形式,如记录、枚举和元组等。fsharp这段代码定义了一个名为Shape的联合类型,它可以是一个圆(包含半径)或一个矩形(包含宽度和高度)。这样,开发者便可以灵活地处理各种形状。F#语言的丰富数据类型使得开发者能够以更高效的方式建模现实世界中的问题。强类型和静态类型确保了在编译时的类型安全,而复合数据类型、枚举、选项和自定义类型提供了灵活性。

2401_90086266的博客 1477

F#入门学习(九)

异常处理 共有两种异常,一种是F#异常,一种是.NET异常,和之前提到的F#库和.NET库一样,看这个语言的视角不同,分法也就不一样。 F#需要用户定义后才能使用,.NET异常可以直接用。 所有.NET异常都继承其框架里面的异常基类Exception类,Exception类有很多属性: StackTrace属性 追踪错误发生位置,包括源文件和行号等信息。 InnerException属性 若...

I_AM_KK的博客 557

【F#初学者】第三讲 可区分联合与其高级运用

F#中的可区分联合

scixing的博客 913

F# 基础

F# 基础 再译《F# 基础》序 前言 第一章     什么是函数编程     函数编程为啥重要     什么是 F#     谁在用F#     谁能读本书 第二章 获得、安装、使用 F# 第三章 函数编程(一)     文字、函数、标识符、标识符的命名、作用域、轻量语法 第三章函数编程(二)     捕获标识符、use

心想事成 3199

F#语言的函数实现

fsharp此处,add是函数名,x和y是函数的参数。fsharplet result = add 3 5 // result 的值为 8。

dbdgxibeifen的博客 466

F# 入门(六):F#中的 for/while循环

首先我们来看看F#中基本的for循环编写方法。 for循环 for语句1 := for 循环变量 = 表达式1 to 表达式2 do 表达式3 done for语句2 := for 循环变量 in 表达式4 do 表达式5done for语句1有点c语言的风格。 for语句2就是一般所说的foreach循环,类似于C#,不过功能更强大。   下面我们来看看第一种for循

fsharp_net的专栏 1359
上一篇: 【函数式编程】【C#/F#】第五讲 函数式编程中的错误处理,副作用管理
下一篇: Microsoft Build 2025重点速览
scixing
博客等级 码龄2年 216粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值