QT6 源(63)篇六:阅读与注释 QString 这个类,包含了 QString 类的 完整源码,也附上 QLatin1String 类的

(9)给出完整的源代码

#ifndef QSTRING_H
#define QSTRING_H

//验证了,没有此宏定义的     #if 不成立
#if defined(QT_NO_CAST_FROM_ASCII) && defined(QT_RESTRICTED_CAST_FROM_ASCII)
#error  QT_NO_CAST_FROM_ASCII and
        QT_RESTRICTED_CAST_FROM_ASCII must not be defined at the same time
#endif

#include <QtCore/qchar.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qarraydata.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qstringliteral.h>
#include <QtCore/qstringalgorithms.h>
#include <QtCore/qanystringview.h>
#include <QtCore/qstringtokenizer.h>

#include <string>
#include <iterator>

#include <stdarg.h>

#ifdef truncate //经验证无此定义,不会报错 error
#error qstring.h must be included before any header file that defines truncate
#endif

#if defined(Q_OS_DARWIN) || defined(Q_QDOC) //不会生成 doc 文档的
Q_FORWARD_DECLARE_CF_TYPE(CFString);
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
#endif

QT_BEGIN_NAMESPACE //说明伟大的 QString 类定义于 QT 全局空间

class QRegularExpression;
class QRegularExpressionMatch;
class QString;

namespace QtPrivate {
template <bool...B> class BoolList;
}

/*
struct QArrayData
{   QBasicAtomicInt ref_ ;
    ArrayOptions    flags;
    qsizetype       alloc;

    static void *   allocate(...) noexcept;
    static void   deallocate(...) noexcept;
};

template <class T>
struct QTypedArrayData : QArrayData {  }; //本类无数据成员

template <class T>
struct QArrayDataPointer //上面的注释给出了学习与阅读本头文件的因缘
{
    Data * d  ; //Data = QTypedArrayData<T> 包含了申请释放内存的成员方法
    T    * ptr; //真正的堆区中的数据起点
    qsizetype size;
};

class QString
{   typedef QTypedArrayData<char16_t> Data; //一个类型定义

    DataPointer d;
  //DataPointer = QStringPrivate = QArrayDataPointer<char16_t>;
}; 本注释用于解释本 QByteArray 类的数据结构的组成
*/
//上面的注释,解释了 QString的数据结构。非常类似于 QByteArray

class Q_CORE_EXPORT QString
{
    typedef QTypedArrayData<char16_t> Data; //一个类型定义

private: //把私有部分放到前面,是因为其中有重要的数据成员定义

#if defined(QT_NO_CAST_FROM_ASCII) //经测试,无此宏定义
    QString &operator+=(const char *s);
    QString &operator+=(const QByteArray &s);
    QString(const char *ch);
    QString(const QByteArray &a);
    QString &operator=(const char  *ch);
    QString &operator=(const QByteArray &a);
#endif

    DataPointer d;  //typedef QStringPrivate DataPointer;
                    //using   QStringPrivate = QArrayDataPointer<char16_t>;
    static const char16_t _empty;

    void reallocData(qsizetype alloc, QArrayData::AllocationOption option);

    void reallocGrowData(qsizetype n);

    static int compare_helper(const QChar *data1, qsizetype length1,
                              const QChar *data2, qsizetype length2,
                              Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;

    static int compare_helper(const QChar *data1, qsizetype length1,
                              const char *data2, qsizetype length2,
                              Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;

    static int localeAwareCompare_helper(const QChar *data1, qsizetype length1,
                                         const QChar *data2, qsizetype length2);

    static QString trimmed_helper(const QString & str);

    static QString trimmed_helper(QString & str);

    static QString simplified_helper(const QString &str);

    static QString simplified_helper(QString &str);

    static QString toLower_helper(const QString &str);

    static QString toLower_helper(QString &str);

    static QString toUpper_helper(const QString &str);

    static QString toUpper_helper(QString &str);

    static QString toCaseFolded_helper(const QString &str);

    static QString toCaseFolded_helper(QString &str);

    static QByteArray toLatin1_helper(const QString &);

    static QByteArray toLatin1_helper_inplace(QString &);

    static QByteArray toUtf8_helper(const QString &);

    static QByteArray toLocal8Bit_helper(const QChar *data, qsizetype size);

    static qsizetype  toUcs4_helper(const ushort *uc, qsizetype length, uint *out);
    // ### Qt 7 char16_t

    static qlonglong  toIntegral_helper(QStringView string, bool *ok, int base);

    static qulonglong toIntegral_helper(QStringView string, bool *ok, uint base);

    void replace_helper(size_t *indices, qsizetype nIndices,
                        qsizetype blen, const QChar *after, qsizetype alen);

    friend class  QStringView; //本类的友元类们
    friend class  QByteArray;
    friend class  QCollator;
    friend struct QAbstractConcatenable;

    template <typename T> static  //静态成员函数
    T toIntegral_helper(QStringView string, bool *ok, int base)
    {
        using Int64 = typename std::conditional<std::is_unsigned<T>::value,
                                                qulonglong,
                                                qlonglong>::type;

        using Int32 = typename std::conditional<std::is_unsigned<T>::value,
                                                uint,
                                                int>::type;

        // we select the right overload by casting base to int or uint
        Int64 val = toIntegral_helper(string, ok, Int32(base));
        if (T(val) != val) {
            if (ok)
                *ok = false;
            val = 0;
        }
        return T(val);
    }

public: //开始重要的公共函数
    typedef QStringPrivate DataPointer; //DataPointer d; 本类的数据成员
    //using QStringPrivate = QArrayDataPointer<char16_t>;

    inline constexpr QString() noexcept { } //默认的构造函数

    QString(qsizetype size, Qt::Initialization);

    QString(qsizetype size, QChar c);
    //Constructs a string of the given size with every character set to c.

    //Constructs a string of size 1 containing the character c.
    QString(      QChar   c);

    explicit
    QString(const QChar * unicode, qsizetype size = -1); //有参构造
    //取 unicode 数组的前  size 个字符
    //Constructs a string initialized with the first size characters of the
    //QChar array unicode. If unicode is 0, a null string is constructed.
    //If size is negative, unicode is assumed to point to a \0'-terminated array
    //and its length is determined dynamically.
    //The terminating null character is not considered part of the string.
    //QString makes a deep copy of the string data.
    //The unicode data is copied as is and
    //the Byte Order Mark is preserved if present.

    QT_ASCII_CAST_WARN inline
    QString(const char       * ch) : QString(fromUtf8(ch)) {}

    QT_ASCII_CAST_WARN inline
    QString(const QByteArray &  a) : QString(fromUtf8(a) ) {}

    explicit
    QString(DataPointer && dd) : d(std::move(dd)) {}

    inline
    QString(QLatin1String latin1)
    { *this = QString::fromLatin1(latin1.data(), latin1.size()); }

#if defined(__cpp_char8_t) || defined(Q_CLANG_QDOC)
    Q_WEAK_OVERLOAD
    inline QString(const char8_t *str)
        : QString(fromUtf8(str))
    {}
#endif

    inline QString(const QString & other) noexcept : d(other.d) { } //copy构造函数

    QString & operator=(const QString &) noexcept;

    inline QString(QString && other) noexcept //移动构造函数
    { qSwap(d, other.d); }

    QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QString)
/*  以宏定义的形式得到本类的 移动赋值运算符函数
#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class) \
    Class &operator=(Class &&other) noexcept { \
        swap(other); \
        return *this; \
    }
*/

    inline ~QString() { } //析构函数

    QString & operator=(      QChar         c); //赋值运算符函数,并构成重载

    QT_ASCII_CAST_WARN inline
    QString & operator=(const char       * ch)
    { return (*this = fromUtf8(ch)); }

    QT_ASCII_CAST_WARN inline
    QString & operator=(const QByteArray &  a)
    { return (*this = fromUtf8(a)); }

    QString & operator=(QLatin1String latin1);

    void swap(QString &other) noexcept { d.swap(other.d); }

//*********************先介绍 QString 里这个独特的用法*********************

    //#define Q_ATTRIBUTE_FORMAT_PRINTF(A, B) \
    //         __attribute__((format(gnu_printf, (A), (B))))
    static QString vasprintf(const char *format, va_list ap) //不必用 va_list
        Q_ATTRIBUTE_FORMAT_PRINTF(1, 0);

    static QString  asprintf(const char * format, ...) //不要用此函数,过时了
        Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
    //Safely builds a formatted string from the format string format and an
    //arbitrary任意 list of arguments.
    //The format string supports the conversion specifiers, length modifiers,
    //and flags provided by printf() in the standard C++ library.
    //The format string and %s arguments must be UTF-8 encoded.
    //安全地从格式字符串 cformat 和任意参数列表构建一个格式化字符串。
    //格式字符串支持标准C++库中printf ()提供的转换说明符、长度修饰符和标志。
    //cformat字符串和%s参数必须使用UTF-8编码。
    //Warning: We do not recommend using QString::asprintf() in new Qt code.
    //Instead, consider using QTextStream or arg(),
    //both of which support Unicode strings seamlessly无缝 and are type-safe.
    //对于翻译,特别是如果字符串包含多个转义序列,您应该考虑使用 arg()函数。
    //这允许翻译人员控制替换的顺序。
    //For translations, especially if the strings contains more than one
    //escape sequence, you should consider using the arg() function instead.
    //This allows the order of the replacements to be controlled by the translator.


    //fieldWidth specifies the minimum amount of space that a is padded to
    //and filled with the character fillChar.
    //A positive value produces right-aligned text;
    //a negative value produces left-aligned text.
    //The base argument specifies the base to use when converting the
    //integer a into a string. The base must be between 2 and 36,
    //with 8 giving octal, 10 decimal, and 16 hexadecimal numbers.
    [[nodiscard]]
    QString arg(short      a, int fieldWidth = 0, int base = 10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qlonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(ushort     a, int fieldWidth = 0, int base = 10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qulonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(int        a, int fieldWidth = 0, int base = 10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qlonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(uint       a, int fieldWidth = 0, int base = 10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qulonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(long       a, int fieldwidth = 0, int base=10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qlonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(ulong      a, int fieldwidth = 0, int base=10,
        QChar fillChar = QLatin1Char(' ')) const
    { return arg(qulonglong(a), fieldWidth, base, fillChar); }

    [[nodiscard]]
    QString arg(qlonglong  a, int fieldwidth = 0, int base=10,
        QChar fillChar = QLatin1Char(' ')) const;

    [[nodiscard]]
    QString arg(qulonglong a, int fieldwidth = 0, int base=10,
        QChar fillChar = QLatin1Char(' ')) const;

    [[nodiscard]]  //这里开始出现不同,出现了浮点数 %e %E %f %g %G
    QString arg(double     a, int fieldWidth = 0,
        char format = 'g', int precision = -1,
        QChar fillChar = QLatin1Char(' ')) const;

    [[nodiscard]]  //The a argument is interpreted as a Latin-1 character.
    QString arg(char       a, int fieldWidth = 0,
        QChar fillChar = QLatin1Char(' ')) const;

    [[nodiscard]]
    QString arg(QChar      a, int fieldWidth = 0,
        QChar fillChar = QLatin1Char(' ')) const;

#if QT_STRINGVIEW_LEVEL < 2
    [[nodiscard]]
    QString arg(const QString & a, int fieldWidth = 0,
        QChar fillChar = QLatin1Char(' ')) const;
    //Returns a copy of this string with the lowest numbered place marker
    //replaced by string a, i.e., %1, %2, ..., %99.
    //返回此字符串的副本,将最低编号的占位符替换为字符串a,即%1,%2,…,%99。
    //fieldWidth specifies the minimum amount of space that argument a shall occupy.
    //If a requires less space than fieldWidth,
    //it is padded to fieldWidth with character fillChar.
    //A positive fieldWidth produces right-aligned text.
    //A negative fieldWidth produces left-aligned text.
#endif

    [[nodiscard]]
    QString arg(QStringView a, int fieldWidth = 0,
        QChar fillChar = QLatin1Char(' ')) const;

    [[nodiscard]]  //说明本 QString类的本函数也接受 QLatin1String类字符作为参数
    QString arg(QLatin1String a, int fieldWidth = 0,
        QChar fillChar = QLatin1Char(' ')) const;

    /*
    template<typename _Tp, _Tp __v>
    struct integral_constant
    {
        static constexpr _Tp                  value = __v;
        typedef _Tp                           value_type;
        typedef integral_constant<_Tp, __v>   type;

        constexpr            operator value_type() const noexcept
        { return value; }

        constexpr value_type operator()()          const noexcept
        { return value; }
    };
*/
private:           //这里突然定义了两个私有的模板类
    template <typename T>  //本类继承自 std 空间里的 integral_constant类
    struct is_convertible_to_view_or_qstring_helper
        : std::integral_constant<bool,
                                 std::is_convertible<T, QString>      ::value ||
                                     std::is_convertible<T, QStringView>  ::value ||
                                     std::is_convertible<T, QLatin1String>::value>
    {};

    template <typename T>  //本类继承自上面的类
    struct is_convertible_to_view_or_qstring
        : is_convertible_to_view_or_qstring_helper<
              typename std::decay<T>::type>
    {};

    /*
template <bool _Test, class _Ty = void>
struct enable_if {};         // no member "type" when !_Test

template <class _Ty>
struct enable_if<true, _Ty>  // type is _Ty for _Test
{
    using type = _Ty;
};
*/
public:  //接着的本 arg() 函数使用了上面的 private 部分里的模板类定义
    template <typename...Args>
    [[nodiscard]]
#ifdef Q_CLANG_QDOC  //这个不成立,看 else分支
    QString
#else
    typename std::enable_if<
        sizeof...(Args) >= 2 && std::is_same<
            QtPrivate::BoolList<is_convertible_to_view_or_qstring<Args>::value..., true>,
            QtPrivate::BoolList<true, is_convertible_to_view_or_qstring<Args>::value...>
            >::value,  QString
        >::type
#endif
    arg(Args &&...args) const  //说明  arg 函数接受可变参
    { return qToStringViewIgnoringNull(*this).arg(std::forward<Args>(args)...); }

//********************以上结束了这个格式化输出的学习注释***********************
//********************以下内容就可以保持与 QByteArray高度的一致性**************

    //Returns the maximum number of characters that can be stored in the
    //string without forcing a reallocation.
    //The sole purpose of this function is to provide a means of fine tuning
    //QString's memory usage. In general,
    //you will rarely ever need to call this function. 不必调用这个函数
    inline qsizetype capacity() const
    { return qsizetype(d->constAllocatedCapacity()); }

    inline qsizetype size    () const { return d.size; }
    inline qsizetype length  () const { return d.size; }
    inline
    qsizetype count(          ) const { return d.size; }

    //Returns the number of occurrences of character ch in the string.
    [[nodiscard]]
    qsizetype count(      QChar           c,
          Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    [[nodiscard]]
    qsizetype count(const QString       & s,
          Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    //Returns the number of (potentially overlapping) occurrences of
    //the string s in this string.

    [[nodiscard]]
    qsizetype count(      QStringView     s,
          Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    inline bool isEmpty   () const { return d.size == 0; }

    inline bool isNull    () const { return d->isNull(); }

    bool isSimpleText () const;

    bool isRightToLeft() const;
    //Returns true if the string is read right to left.

    [[nodiscard]]
    bool isValidUtf16 () const noexcept
    { return QStringView(*this).isValidUtf16(); }
    //如果字符串包含有效的 UTF-16 编码数据,则返回 true,否则返回 false。
    //请注意,此函数不会对数据进行任何特殊的验证;它只是检查是否可以成功从 UTF-16 解码。
    //数据假定为主机字节顺序;BOM 的存在毫无意义。

    inline bool isDetached() const { return !d->isShared(); }

    inline bool isSharedWith(const QString & other) const
    { return d.isSharedWith(other.d); }

    //如果字符串是大写字母,则返回true,即它与 toUpper()折叠相同。
    //请注意,这并不意味着字符串不包含小写字母(一些小写字母没有大写字母的折叠它们保持不变)。
    //有关更多信息,请参见Unicode标准第3.13节。
    bool isUpper() const;

    bool isLower() const;
    //Note that this does not mean that the string does not contain
    //uppercase letters (some uppercase letters do not have a lowercase folding;
    //they are left unchanged by toLower()).

    inline       DataPointer & data_ptr()       { return d; } //其返回的对象没用
    inline const DataPointer & data_ptr() const { return d; }

    inline const QChar * data() const
    {
#if QT5_NULL_STRINGS == 1
        return reinterpret_cast<const QChar *>(d.data() ? d.data() : &_empty);
#else
        return reinterpret_cast<const QChar *>(d.data());
#endif
    }

    inline       QChar * data() //返回封装的 QChar数组的起始地址
    {
        detach();
        Q_ASSERT(d.data());

        return reinterpret_cast<QChar *>(d.data());
    }

    inline const QChar * constData() const { return data(); }

    inline const QChar * unicode  () const { return data(); } //等价于 data()
    //Returns a Unicode representation of the string.
    //The result remains valid until the string is modified.
    //Note: The returned string may not be '\0'-terminated.
    //      Use size() to determine the length of the array.


    //Returns the index position of the first occurrence of the character c
    //in the string, searching forward from index position from.
    //Returns -1 if ch could not be found.
    [[nodiscard]]
    qsizetype indexOf(QChar           c, qsizetype from = 0,
            Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

#if QT_STRINGVIEW_LEVEL < 2
    [[nodiscard]]
    qsizetype indexOf(const QString & s, qsizetype from = 0,
            Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#endif

    [[nodiscard]]
    qsizetype indexOf(QLatin1String   s, qsizetype from = 0,
            Qt::CaseSensitivity cs = Qt::CaseSensitive) const;


    [[nodiscard]]
    qsizetype indexOf(QStringView     s, qsizetype from = 0,
            Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return QtPrivate::findString(*this, from, s, cs); }

    //Returns the index position of the last occurrence of the character c,
    //searching backward from position from.
    [[nodiscard]]
    qsizetype lastIndexOf(      QChar     c, qsizetype from = -1,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    //Qt::CaseSensitivity {  CaseInsensitive, CaseSensitive };

#if QT_STRINGVIEW_LEVEL < 2
    //Returns the index position of the last occurrence of the string s in this string,
    //searching backward from index position from.
    //If from is -1, the search starts at the last character;
    //if from is -2, at the next to last character and so on.
    //Returns -1 if str is not found.
    //If cs is Qt::CaseSensitive (default), the search is case sensitive;
    //otherwise the search is case insensitive.
    [[nodiscard]]  //对于字符串的匹配,要求所有字符的完全匹配,否则返回 -1
    qsizetype lastIndexOf(const QString & s, qsizetype from,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    [[nodiscard]]
    qsizetype lastIndexOf(const QString & s, //调用了上面的重载函数
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const
    { return  lastIndexOf(s, size(), cs); }
    //Returns the index position of the last occurrence of the string s in this
    //string. Returns -1 if str is not found.
#endif

    [[nodiscard]]
    qsizetype lastIndexOf(QLatin1String   s,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const
    { return lastIndexOf(s, size(), cs); }

    [[nodiscard]]
    qsizetype lastIndexOf(QLatin1String   s, qsizetype from,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    [[nodiscard]]
    qsizetype lastIndexOf(QStringView     s,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return lastIndexOf(s, size(), cs); }

    [[nodiscard]]
    qsizetype lastIndexOf(QStringView     s, qsizetype from,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return QtPrivate::lastIndexOf(*this, from, s, cs); }

#if QT_CONFIG(regularexpression)  //经测试是允许正则表达式的
    [[nodiscard]]
    qsizetype indexOf(const QRegularExpression &re, qsizetype from = 0,
            QRegularExpressionMatch *rmatch = nullptr) const;

#ifdef Q_QDOC
    [[nodiscard]]
    qsizetype lastIndexOf(const QRegularExpression &re,
                QRegularExpressionMatch *rmatch = nullptr) const;
#else
    // prevent an ambiguity when called like this: lastIndexOf(re, 0)
    template <typename T = QRegularExpressionMatch,
             std::enable_if_t<
                 std::is_same_v<T, QRegularExpressionMatch>,
                 bool> = false>
    [[nodiscard]]
    qsizetype lastIndexOf(const QRegularExpression &re, T *rmatch = nullptr) const
    { return lastIndexOf(re, size(), rmatch); }
#endif

    [[nodiscard]]
    qsizetype lastIndexOf(const QRegularExpression &re, qsizetype from,
                QRegularExpressionMatch *rmatch = nullptr) const;

    [[nodiscard]]
    bool contains(const QRegularExpression &re,
             QRegularExpressionMatch *rmatch = nullptr) const;

    [[nodiscard]]
    qsizetype count(const QRegularExpression &re) const;
#endif //#if QT_CONFIG(regularexpression)


    [[nodiscard]] inline bool contains(      QChar           c,
                                       Qt::CaseSensitivity cs = Qt::CaseSensitive) const
    { return indexOf(c, 0, cs) != -1; }


#if QT_STRINGVIEW_LEVEL < 2  //对于字符串的匹配,要求所有字符的完全匹配,否则返回 -1
    [[nodiscard]] inline bool contains(const QString       & s,
                                       Qt::CaseSensitivity cs = Qt::CaseSensitive) const
    { return indexOf(s, 0, cs) != -1; }
#endif

    [[nodiscard]] inline bool contains(      QLatin1String   s,
                                       Qt::CaseSensitivity cs = Qt::CaseSensitive) const
    { return indexOf(s, 0, cs) != -1; }


    [[nodiscard]] inline bool contains(      QStringView     s,
                                       Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return indexOf(s, 0, cs) != -1; }

    bool startsWith(      QChar           c,
                    Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

#if QT_STRINGVIEW_LEVEL < 2 //Returns true if the string starts with s;
    bool startsWith(const QString       & s, //otherwise returns false.
                    Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#endif

    [[nodiscard]]
    bool startsWith(      QStringView     s,
               Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return QtPrivate::startsWith(*this, s, cs); }

    bool startsWith(      QLatin1String   s,
                    Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    bool endsWith  (      QChar c,
                  Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

#if QT_STRINGVIEW_LEVEL < 2 //Returns true if the string ends with s;
    bool endsWith  (const QString       & s, //otherwise returns false.
                  Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#endif

    [[nodiscard]]
    bool endsWith  (      QStringView     s,
             Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return QtPrivate::endsWith(*this, s, cs); }

    bool endsWith  (      QLatin1String   s,
                  Qt::CaseSensitivity cs = Qt::CaseSensitive) const;


    inline const QChar at(qsizetype i) const //值返回
    {
        Q_ASSERT(size_t(i) < size_t(size()));
        return QChar(d.data()[i]);
    }

    const         QChar   operator[](qsizetype i) const
    {
        Q_ASSERT(size_t(i) < size_t(size()));
        return QChar(d.data()[i]);
    }

    [[nodiscard]] QChar & operator[](qsizetype i) //有 const 修饰符修饰 this
    { Q_ASSERT(i >= 0 && i < size()); return data()[i]; }

    [[nodiscard]] inline QChar   front() const { return at(0); }
    [[nodiscard]] inline QChar & front()       { return operator[](0); }

    [[nodiscard]] inline QChar   back () const { return at(size() - 1); }
    [[nodiscard]] inline QChar & back ()       { return operator[](size() - 1); }

    //Returns a substring that contains the n leftmost characters of the string.
    //If you know that n cannot be out of bounds, use first() instead in new code,
    [[nodiscard]]  //because it is faster.
    QString left  (qsizetype n) const;  //等价于 新代码的 first()

    //Returns a substring that contains the n rightmost characters of the string.
    [[nodiscard]]  //新代码用 last(),更快
    QString right (qsizetype n) const;

    //Returns a string that contains n characters of this string,
    [[nodiscard]] //starting at the specified position index.新代码用 sliced()更快
    QString mid   (qsizetype position, qsizetype n = -1) const;

    [[nodiscard]]
    QString first (qsizetype n) const
    {   Q_ASSERT(n >= 0);
        Q_ASSERT(n <= size());
        return QString(data(), n);
    }

    [[nodiscard]]
    QString last  (qsizetype n) const
    {   Q_ASSERT(n >= 0);
        Q_ASSERT(n <= size());
        return QString(data() + size() - n, n);
    }

    [[nodiscard]]
    QString sliced(qsizetype pos) const //从字符串的中间位置 pos取一些字符
    {   Q_ASSERT(pos >= 0);
        Q_ASSERT(pos <= size());
        return QString(data() + pos, size() - pos);
    }

    [[nodiscard]]
    QString sliced(qsizetype pos, qsizetype n) const
    {   Q_ASSERT(pos >= 0);
        Q_ASSERT(n >= 0);
        Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size()));
        return QString(data() + pos, n);
    }

    //Returns a string that contains the size() - n leftmost characters of
    //this string.
    [[nodiscard]] //裁掉右边的 n个字符后返回
    QString chopped(qsizetype n) const
    {   Q_ASSERT(n >= 0);
        Q_ASSERT(n <= size());
        return first(size() - n);
    }
    //void  chop   (qsizetype n)  ; //形参是被裁的数量。此函在前面的间隔 500行
    //Removes n characters from the end of the string.

#if !defined(Q_CLANG_QDOC)
    [[nodiscard]] QString trimmed() const &
    { return trimmed_helper(*this); }

    [[nodiscard]] QString trimmed() &&
    { return trimmed_helper(*this); }

    [[nodiscard]] QString simplified() const &
    { return simplified_helper(*this); }

    [[nodiscard]] QString simplified() &&
    { return simplified_helper(*this); }

    [[nodiscard]] QString toLower() const &
    { return toLower_helper(*this); }

    [[nodiscard]] QString toLower() &&
    { return toLower_helper(*this); }

    [[nodiscard]] QString toUpper() const &
    { return toUpper_helper(*this); }

    [[nodiscard]] QString toUpper() &&
    { return toUpper_helper(*this); }

    //Returns the case folded equivalent of the string.
    //For most Unicode characters this is the same as toLower().
    [[nodiscard]] QString toCaseFolded() const & //返回小写形式
    { return toCaseFolded_helper(*this); }

    [[nodiscard]] QString toCaseFolded() &&
    { return toCaseFolded_helper(*this); }
#else
    [[nodiscard]] QString toLower() const;
    [[nodiscard]] QString toUpper() const;
    [[nodiscard]] QString toCaseFolded() const;
    [[nodiscard]] QString trimmed() const;
    [[nodiscard]] QString simplified() const;
#endif

    //将纯文本字符串转换为带有 HTML实体替换的 HTML字符串,HTML实体包括<、>、&和"
    //Converts a plain text string to an HTML string with HTML metacharacters <,
    //>, &, and " replaced by HTML entities.
    [[nodiscard]] QString toHtmlEscaped() const;

    //Returns a string of size width that contains this string padded
    //by the fill character.
    //返回一个指定长度的新 QString,原内容左对齐,右侧填充指定的字符,默认是空格。
    //函数可能有参数指定填充字符和是否截断原内容。
    //当原数组长度小于width时,右侧填充fill字符;
    //如果原长度超过width,是否截取取决于truncate参数是否为true。
    [[nodiscard]]
    QString leftJustified (qsizetype width, QChar fill = QLatin1Char(' '),
                  bool trunc = false) const;

    [[nodiscard]]
    QString rightJustified(qsizetype width, QChar fill = QLatin1Char(' '),
                   bool trunc = false) const;

    enum SectionFlag {
        SectionDefault             = 0x00,
        SectionSkipEmpty           = 0x01, //忽略空白符
        SectionIncludeLeadingSep   = 0x02, //下面函数的官方注释很重要
        SectionIncludeTrailingSep  = 0x04,
        SectionCaseInsensitiveSeps = 0x08
    };
    Q_DECLARE_FLAGS(SectionFlags, SectionFlag)
    //等于定义了 SectionFlags = QFlags<SectionFlag>

    //此函数返回字符串的一部分。这个字符串被当作由字符'sep'分隔的字段的序列来处理。
    //返回的字符串由从位置`start'到位置`end`(包括)的字段组成。
    //如果未指定、end`,则包括从位置start`到字符串结尾的所有字段。
    //字段从左到右编号 0、1、2等,从右到左编号 -1、-2等。
    //flags 参数可用于影响函数行为的一些方面,例如是否区分大小写,
    //是否跳过空字段以及如何处理前导和尾随分隔符;请参阅 SectionFlags。
    //If start or end is negative, we count fields from the right of the string,
    //the right-most field being -1, the one from right-most field being -2,
    //and so on.  总之,这里把 QString里的字符串看成是分段的,分隔符是 sep。
    [[nodiscard]] //这里的下标 start不是数组下标,而是分段后的子字符串的序号。
    QString section(      QChar     sep   , //注意 sep左边的第一段的序号是 0,即使为空
            qsizetype start, qsizetype end = -1,
            SectionFlags flags = SectionDefault) const
    { return section(QString(sep), start, end, flags); }

    [[nodiscard]]
    QString section(const QString & in_sep,
            qsizetype start, qsizetype end = -1,
            SectionFlags flags = SectionDefault) const;

#if QT_CONFIG(regularexpression)
    [[nodiscard]]
    QString section(const QRegularExpression &re,
            qsizetype start, qsizetype end = -1,
            SectionFlags flags = SectionDefault) const;
#endif


public:
    //enum SplitBehaviorFlags { KeepEmptyParts = 0, SkipEmptyParts = 0x1, };
    [[nodiscard]]  //using QStringList = QList<QString>;
    QStringList split(      QChar                sep,
          Qt::SplitBehavior behavior = Qt::KeepEmptyParts,
          Qt::CaseSensitivity     cs = Qt::CaseSensitive) const;

    [[nodiscard]]
    QStringList split(const QString            & sep,
          Qt::SplitBehavior behavior = Qt::KeepEmptyParts,
          Qt::CaseSensitivity     cs = Qt::CaseSensitive) const;
    //Splits the string into substrings wherever sep occurs,
    //and returns the list of those strings.
    //If sep does not match anywhere in the string,
    //split() returns a single-element list containing this string.
    //cs specifies whether sep should be matched case sensitively or
    //case insensitively.
    //If behavior is Qt::SkipEmptyParts, empty entries don't appear in the result.
    //By default, empty entries are kept.

#ifndef QT_NO_REGULAREXPRESSION
    [[nodiscard]]
    QStringList split(const QRegularExpression & sep,
          Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const;
#endif


    template <typename Needle, typename...Flags> //这些不懂,先留这里
    [[nodiscard]] inline
    auto tokenize(Needle &&needle, Flags...flags) const &
        noexcept(noexcept(qTokenize(std::declval<const QString &>(),
                                    std::forward<Needle>(needle), flags...)))
        -> decltype(qTokenize(*this, std::forward<Needle>(needle), flags...))
    {   return qTokenize(qToStringViewIgnoringNull(*this),
                         std::forward<Needle>(needle), flags...);
    }

    template <typename Needle, typename...Flags>
    [[nodiscard]] inline
    auto tokenize(Needle &&needle, Flags...flags) const &&
        noexcept(noexcept(qTokenize(std::declval<const QString>(),
                                    std::forward<Needle>(needle), flags...)))
        -> decltype(qTokenize(std::move(*this),
                              std::forward<Needle>(needle), flags...))
    {   return qTokenize(std::move(*this),
                         std::forward<Needle>(needle), flags...);
    }

    template <typename Needle, typename...Flags>
    [[nodiscard]] inline
    auto tokenize(Needle &&needle, Flags...flags) &&
        noexcept(noexcept(qTokenize(std::declval<QString>(),
                                    std::forward<Needle>(needle), flags...)))
        -> decltype(qTokenize(std::move(*this),
                              std::forward<Needle>(needle), flags...))
    {   return qTokenize(std::move(*this),
                         std::forward<Needle>(needle), flags...);
    }


    enum NormalizationForm {
        NormalizationForm_D,
        NormalizationForm_C,
        NormalizationForm_KD,
        NormalizationForm_KC
    };

    [[nodiscard]] QString normalized(NormalizationForm mode,
        QChar::UnicodeVersion version = QChar::Unicode_Unassigned) const;
    //Returns the string in the given Unicode normalization mode,
    //according to the given version of the Unicode standard.

    //Returns a copy of this string repeated the specified number of times.
    //If times is less than 1, an empty string is returned.
    [[nodiscard]] QString repeated(qsizetype times) const;

    //Returns the QString as a '\0'-terminated array of unsigned shorts.
    //The result remains valid until the string is modified.
    //The returned string is in host byte order.
    const ushort * utf16() const; // ### Qt 7 char16_t

    //Returns the string converted to an int using base base,
    //which is 10 by default and must be between 2 and 36, or 0.
    //Returns 0 if the conversion fails.
    //If ok is not nullptr, failure is reported by setting *ok to false,
    //and success by setting *ok to true.
    //If base is 0, the C language convention is used:
    //If the string begins with "0x", base 16 is used;
    //if the string begins with "0", base 8 is used; otherwise, base 10 is used.
    //The string conversion will always happen in the 'C' locale.
    //For locale-dependent conversion use QLocale::toInt()
    short      toShort    (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<short>(*this, ok, base); }

    ushort     toUShort   (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<ushort>(*this, ok, base); }

    int        toInt      (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<int>(*this, ok, base); }

    uint       toUInt     (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<uint>(*this, ok, base); }

    long       toLong     (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<long>(*this, ok, base); }

    ulong      toULong    (bool * ok=nullptr, int base = 10) const
    { return toIntegral_helper<ulong>(*this, ok, base); }

    qlonglong  toLongLong (bool * ok=nullptr, int base = 10) const;
    qulonglong toULongLong(bool * ok=nullptr, int base = 10) const;
    float      toFloat    (bool * ok=nullptr               ) const;
    double     toDouble   (bool * ok=nullptr               ) const;

#if !defined(Q_CLANG_QDOC)
    [[nodiscard]] QByteArray toLatin1() const &
    { return toLatin1_helper(*this); }

    [[nodiscard]] QByteArray toLatin1() &&
    { return toLatin1_helper_inplace(*this); }

    [[nodiscard]] QByteArray toUtf8() const &
    { return toUtf8_helper(*this); }

    [[nodiscard]] QByteArray toUtf8() &&
    { return toUtf8_helper(*this); }

    //返回字符串的本地8位表示形式,作为QByteArray。
    //如果字符串包含本地8位编码不支持字符,则返回的字节数组是未定义的。
    //在Unix系统中,这等同于toUtf8(),在Windows系统中,当前代码页被使用。
    //如果该字符串包含任何无法在本地编码的字符,则返回的字节数组是未定义的。
    //这些字符可能被抑制或替换为另一个。
    [[nodiscard]] QByteArray toLocal8Bit() const &
    { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }

    [[nodiscard]] QByteArray toLocal8Bit() &&
    { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
#else
    [[nodiscard]] QByteArray toLatin1() const;
    [[nodiscard]] QByteArray toUtf8() const;
    [[nodiscard]] QByteArray toLocal8Bit() const;
#endif

    [[nodiscard]] QList<uint> toUcs4() const; // ### Qt 7 char32_t

    inline std::string        toStdString() const
    { return toUtf8().toStdString(); }

    inline std::wstring       toStdWString() const
    {
        std::wstring str;
        str.resize(length());
#if __cplusplus >= 201703L
        str.resize(toWCharArray(str.data()));
#else
        if (length())
            str.resize(toWCharArray(&str.front()));
#endif
        return str;
    }

    inline std::u16string    toStdU16String() const
    { return std::u16string(reinterpret_cast<const char16_t*>(utf16()), length()); }

    inline std::u32string    toStdU32String() const
    {
        std::u32string u32str(length(), char32_t(0));
        qsizetype len = toUcs4_helper(reinterpret_cast<const ushort *>(constData()),
                                      length(), reinterpret_cast<uint*>(&u32str[0]));
        u32str.resize(len);
        return u32str;
    }

    static inline QString fromStdString   (const std::string & s)
    { return fromUtf8(s.data(), int(s.size())); }

    static inline QString fromStdWString  (const std::wstring &s)
    { return fromWCharArray(s.data(), int(s.size())); }

    static inline QString fromStdU16String(const std::u16string &s)
    { return fromUtf16(s.data(), int(s.size())); }

    static inline QString fromStdU32String(const std::u32string &s)
    { return fromUcs4(s.data(), int(s.size())); }

    // note - this are all inline so we can benefit from
    //strlen() compile time optimizations     以下全是静态的成员函数
    static        QString fromLatin1(     QByteArrayView    ba);
    Q_WEAK_OVERLOAD
    static inline QString fromLatin1(const QByteArray     & ba)
    { return fromLatin1(QByteArrayView(ba)); }

    //Returns a QString initialized with the first size characters of the
    //Latin-1 string str.
    //If size is -1, strlen(str) is used instead.
    static inline QString fromLatin1(const char * str, qsizetype size)
    {
        return fromLatin1(QByteArrayView(str, !str || size < 0
                                                ? qstrlen(str) : size));
    }

    static        QString fromUtf8(      QByteArrayView   utf8);
    Q_WEAK_OVERLOAD
    static inline QString fromUtf8(const QByteArray     & ba  )
    { return fromUtf8(QByteArrayView(ba)); }

    static inline QString fromUtf8(const char           * utf8, qsizetype size)
    {
        return fromUtf8(QByteArrayView(utf8, !utf8 || size < 0
                                               ? qstrlen(utf8) : size));
    }

    static        QString fromLocal8Bit(      QByteArrayView   ba);
    Q_WEAK_OVERLOAD
    static inline QString fromLocal8Bit(const QByteArray     & ba)
    { return fromLocal8Bit(QByteArrayView(ba)); }

    static inline QString fromLocal8Bit(const char           * str, qsizetype size)
    {
        return fromLocal8Bit(QByteArrayView(str, !str || size < 0
                                                   ? qstrlen(str) : size));
    }

    static       QString fromRawData(const QChar    *, qsizetype size     );
    static       QString fromUtf16  (const char16_t *, qsizetype size = -1);
    static       QString fromUcs4   (const char32_t *, qsizetype size = -1);

#if QT_DEPRECATED_SINCE(6, 0) //函数 fromUtf16()、fromUcs4 的重载版本作废了
    QT_DEPRECATED_VERSION_X_6_0("Use char16_t * overload.")
    static       QString fromUtf16(const ushort *str, qsizetype size = -1)
    { return fromUtf16(reinterpret_cast<const char16_t *>(str), size); }

    QT_DEPRECATED_VERSION_X_6_0("Use char32_t * overload.")
    static       QString fromUcs4(const uint *str, qsizetype size = -1)
    { return fromUcs4(reinterpret_cast<const char32_t *>(str), size); }
#endif

#if defined(__cpp_char8_t) || defined(Q_CLANG_QDOC)
    Q_WEAK_OVERLOAD
    static inline QString fromUtf8(const char8_t *str)
    { return fromUtf8(reinterpret_cast<const char *>(str)); }
    Q_WEAK_OVERLOAD
    static inline QString fromUtf8(const char8_t *str, qsizetype size)
    { return fromUtf8(reinterpret_cast<const char *>(str), size); }
#endif

    //用本 QString对象中的数据填充形参数组 array。
    //The array is encoded in UTF-16 on platforms where wchar_t is 2 bytes wide
    //(e.g. windows) and in UCS-4 on platforms where wchar_t is 4 bytes wide
    //(most Unix systems).
    //数组 array必须由调用者分配,并包含足够的空间来容纳完整的字符串
    //(分配与字符串长度相同的数组总是足够的)。
    //此函数返回数组中字符串的实际长度。    注意:此函数不会在数组中添加空字符。
           inline qsizetype toWCharArray  (      wchar_t * array) const
    {
        return qToStringViewIgnoringNull(*this).toWCharArray(array);
    }

    [[nodiscard]]
    static inline QString   fromWCharArray(const wchar_t * string,
                                                       qsizetype size = -1)
    {
        return sizeof(wchar_t) == sizeof(QChar)
                ? fromUtf16(reinterpret_cast<const char16_t *>(string), size)
                : fromUcs4 (reinterpret_cast<const char32_t *>(string), size);
    }
    //Returns a copy of the string, where the encoding of string depends on the
    //size of wchar. If wchar is 4 bytes, the string is interpreted as UCS-4,
    //if wchar is 2 bytes it is interpreted as UTF-16.
    //If size is -1 (default), the string must be '\0'-terminated.

    //Performs a comparison of this with ch, using the case sensitivity setting cs.
    int compare(      QChar          ch,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return compare(QStringView{&ch, 1}, cs); }

    //Lexically compares this string with the other string and
    //returns an integer less than, equal to,
    //or greater than zero if this string is less than, equal to,
    //or greater than the other string.
#if QT_STRINGVIEW_LEVEL < 2
    int compare(const QString       & s,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
#endif

    int compare(      QLatin1String   other,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;

    inline
    int compare(      QStringView     s,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
    { return -s.compare(*this, cs); }


    //Compares s1 with s2 and returns an integer less than, equal to,
    //or greater than zero if s1 is less than, equal to, or greater than s2.
    //If cs is Qt::CaseSensitive, the comparison is case sensitive;
    //otherwise the comparison is case insensitive.
    //Case sensitive comparison is based exclusively on the numeric
    //Unicode values of the characters and is very fast,
    //but is not what a human would expect.
    //Consider sorting user-visible strings with localeAwareCompare().
    static inline // 其实还是静态函数版本更好用
    int compare(const QString       & s1, const QString       & s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
    { return s1.compare(s2, cs); }

    static inline
    int compare(const QString       & s1,       QLatin1String   s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
    { return s1.compare(s2, cs); }

    static
    int compare(const QString       & s1,       QStringView     s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
    { return s1.compare(s2, cs); }

    static inline
    int compare(      QLatin1String   s1, const QString       & s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
    { return -s2.compare(s1, cs); }

    static
    int compare(      QStringView     s1, const QString       & s2,
                Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
    { return -s2.compare(s1, cs); }

    int localeAwareCompare(const QString     & s) const;

    int localeAwareCompare(      QStringView   s) const
    { return localeAwareCompare_helper(constData(), length(),
                                         s.constData(), s.length());
    }

    //Compares s1 with s2 and returns an integer less than, equal to,
    //or greater than zero if s1 is less than, equal to, or greater than s2.
    //The comparison is performed in a locale- and also platform-dependent manner.
    //Use this function to present sorted lists of strings to the user.
    static
    int localeAwareCompare(const QString     & s1, const QString     & s2)
    { return s1.localeAwareCompare(s2); }

    static
    int localeAwareCompare(      QStringView   s1,       QStringView   s2)
    { return localeAwareCompare_helper(s1.constData(), s1.length(),
                                       s2.constData(), s2.length());
    }

    QT_ASCII_CAST_WARN inline
    bool operator==(const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) == 0; }

    QT_ASCII_CAST_WARN inline
    bool operator!=(const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) != 0; }

    QT_ASCII_CAST_WARN inline
    bool operator< (const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) < 0; }

    QT_ASCII_CAST_WARN inline
    bool operator<=(const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) <= 0; }

    QT_ASCII_CAST_WARN inline
    bool operator> (const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) > 0; }

    QT_ASCII_CAST_WARN inline
    bool operator>=(const char * s) const
    { return QString::compare_helper(constData(), size(), s, -1) >= 0; }

    QT_ASCII_CAST_WARN inline
    bool operator==(const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) == 0; }

    QT_ASCII_CAST_WARN inline
    bool operator!=(const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) != 0; }

    QT_ASCII_CAST_WARN inline
    bool operator< (const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) < 0; }

    QT_ASCII_CAST_WARN inline
    bool operator> (const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) > 0; }

    QT_ASCII_CAST_WARN inline
    bool operator<=(const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) <= 0; }

    QT_ASCII_CAST_WARN inline
    bool operator>=(const QByteArray & s) const
    { return QString::compare_helper(constData(), size(),
                                   s.constData(), s.size()) >= 0; }

    QT_ASCII_CAST_WARN friend  //以下开始全局函数
    bool operator==(const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) == 0; }

    QT_ASCII_CAST_WARN friend
    bool operator!=(const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) != 0; }

    QT_ASCII_CAST_WARN friend
    bool operator< (const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) > 0; }

    QT_ASCII_CAST_WARN friend
    bool operator> (const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) < 0; }

    QT_ASCII_CAST_WARN friend
    bool operator<=(const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) >= 0; }

    QT_ASCII_CAST_WARN friend
    bool operator>=(const char * s1, const QString & s2)
    { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) <= 0; }

    friend  //友元函数,这是全局函数,定义的全局比较运算符函数
    bool operator==(const QString & s1, const QString & s2) noexcept
    {   return (s1.size() == s2.size())
               && QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) == 0;
    }

    friend
    bool operator!=(const QString & s1, const QString & s2) noexcept
    { return !(s1 == s2); }

    friend
    bool operator< (const QString & s1, const QString & s2) noexcept
    {   return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; }

    friend
    bool operator> (const QString & s1, const QString & s2) noexcept
    { return s2 < s1; }

    friend
    bool operator<=(const QString & s1, const QString & s2) noexcept
    { return !(s1 > s2); }

    friend
    bool operator>=(const QString & s1, const QString & s2) noexcept
    { return !(s1 < s2); }

    friend
    bool operator==(const QString &s1, QLatin1String s2) noexcept
    {   return (s1.size() == s2.size())
               && QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) == 0;
    }

    friend
    bool operator< (const QString &s1, QLatin1String s2) noexcept
    { return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; }

    friend
    bool operator> (const QString &s1, QLatin1String s2) noexcept
    { return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) > 0; }

    friend
    bool operator!=(const QString &s1, QLatin1String s2) noexcept
    { return !(s1 == s2); }

    friend
    bool operator<=(const QString &s1, QLatin1String s2) noexcept
    { return !(s1 > s2); }

    friend
    bool operator>=(const QString &s1, QLatin1String s2) noexcept
    { return !(s1 < s2); }

    friend
    bool operator==(QLatin1String s1, const QString &s2) noexcept
    { return s2 == s1; }

    friend
    bool operator< (QLatin1String s1, const QString &s2) noexcept
    { return s2 > s1; }

    friend
    bool operator> (QLatin1String s1, const QString &s2) noexcept
    { return s2 < s1; }

    friend
    bool operator!=(QLatin1String s1, const QString &s2) noexcept
    { return s2 != s1; }

    friend
    bool operator<=(QLatin1String s1, const QString &s2) noexcept
    { return s2 >= s1; }

    friend
    bool operator>=(QLatin1String s1, const QString &s2) noexcept
    { return s2 <= s1; }

    // Check isEmpty() instead of isNull() for backwards compatibility.
    friend
    bool operator==(const QString &s1, std::nullptr_t) noexcept
    { return s1.isEmpty(); }

    friend
    bool operator!=(const QString &s1, std::nullptr_t) noexcept
    { return !s1.isEmpty(); }

    friend
    bool operator< (const QString &  , std::nullptr_t) noexcept
    { return false; }

    friend
    bool operator> (const QString &s1, std::nullptr_t) noexcept
    { return !s1.isEmpty(); }

    friend
    bool operator<=(const QString &s1, std::nullptr_t) noexcept
    { return s1.isEmpty(); }

    friend
    bool operator>=(const QString &  , std::nullptr_t) noexcept
    { return true; }

    friend
    bool operator==(std::nullptr_t, const QString &s2) noexcept
    { return s2 == nullptr; }

    friend
    bool operator!=(std::nullptr_t, const QString &s2) noexcept
    { return s2 != nullptr; }

    friend
    bool operator< (std::nullptr_t, const QString &s2) noexcept
    { return s2 >  nullptr; }

    friend
    bool operator> (std::nullptr_t, const QString &s2) noexcept
    { return s2 <  nullptr; }

    friend
    bool operator<=(std::nullptr_t, const QString &s2) noexcept
    { return s2 >= nullptr; }

    friend
    bool operator>=(std::nullptr_t, const QString &s2) noexcept
    { return s2 <= nullptr; }

    friend
    bool operator==(const QString &s1, const char16_t *s2) noexcept
    { return s1 == QStringView(s2); }

    friend
    bool operator!=(const QString &s1, const char16_t *s2) noexcept
    { return s1 != QStringView(s2); }

    friend
    bool operator< (const QString &s1, const char16_t *s2) noexcept
    { return s1 <  QStringView(s2); }

    friend
    bool operator> (const QString &s1, const char16_t *s2) noexcept
    { return s1 >  QStringView(s2); }

    friend
    bool operator<=(const QString &s1, const char16_t *s2) noexcept
    { return s1 <= QStringView(s2); }

    friend
    bool operator>=(const QString &s1, const char16_t *s2) noexcept
    { return s1 >= QStringView(s2); }

    friend
    bool operator==(const char16_t *s1, const QString &s2) noexcept
    { return s2 == s1; }

    friend
    bool operator!=(const char16_t *s1, const QString &s2) noexcept
    { return s2 != s1; }

    friend
    bool operator< (const char16_t *s1, const QString &s2) noexcept
    { return s2 >  s1; }

    friend
    bool operator> (const char16_t *s1, const QString &s2) noexcept
    { return s2 <  s1; }

    friend
    bool operator<=(const char16_t *s1, const QString &s2) noexcept
    { return s2 >= s1; }

    friend
    bool operator>=(const char16_t *s1, const QString &s2) noexcept
    { return s2 <= s1; }

    // QChar <> QString
    friend inline
    bool operator==(QChar lhs, const QString &rhs) noexcept
    { return rhs.size() == 1 && lhs == rhs.front(); }

    friend inline
    bool operator!=(QChar lhs, const QString &rhs) noexcept
    { return !(lhs == rhs); }

    friend inline
    bool operator< (QChar lhs, const QString &rhs) noexcept
    { return compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }

    friend inline
    bool operator> (QChar lhs, const QString &rhs) noexcept
    { return compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; }

    friend inline
    bool operator<=(QChar lhs, const QString &rhs) noexcept
    { return !(lhs >  rhs); }

    friend inline
    bool operator>=(QChar lhs, const QString &rhs) noexcept
    { return !(lhs <  rhs); }

    friend inline
    bool operator==(const QString &lhs, QChar rhs) noexcept
    { return   rhs == lhs; }

    friend inline
    bool operator!=(const QString &lhs, QChar rhs) noexcept
    { return !(rhs == lhs); }

    friend inline
    bool operator< (const QString &lhs, QChar rhs) noexcept
    { return   rhs >  lhs; }

    friend inline
    bool operator> (const QString &lhs, QChar rhs) noexcept
    { return   rhs <  lhs; }

    friend inline
    bool operator<=(const QString &lhs, QChar rhs) noexcept
    { return !(rhs <  lhs); }

    friend inline
    bool operator>=(const QString &lhs, QChar rhs) noexcept
    { return !(rhs >  lhs); }

    //-------------以上全是关于 QString 的读函数>>>>>>>>>>>>>>>>>
    //-------------接着开始阅读对 QString进行修改的写函数>>>>>>>>>>

    inline void detach()
    { if (d->needsDetach()) reallocData(d.size, QArrayData::KeepSize); }

    //Resets the QString to use the first size Unicode characters in the
    //array unicode. The data in unicode is not copied. //不要修改 unicode数组
    //The caller must be able to guarantee that unicode will not be deleted or
    //modified as long as the QString (or an unmodified copy of it) exists.
    //可以使用此函数代替 fromRawData()来重用现有的 QString 对象,以节省内存重新分配。
    QString & setRawData(const QChar  * unicode, qsizetype  size);
    QString & setUnicode(const QChar  * unicode, qsizetype  size);
    //Resizes the string to size characters and
    //copies unicode into the string.
    //If unicode is nullptr, nothing is copied,
    //but the string is still resized to size.

    inline
    QString & setUtf16  (const ushort * autf16 , qsizetype asize)
    {   return setUnicode(reinterpret_cast<const QChar *>(autf16), asize); }
    // ### Qt 7 char16_t
    //Resizes the string to size characters and copies unicode into the string.
    //If unicode is nullptr, nothing is copied,
    //but the string is still resized to size.
    //Note that unlike fromUtf16(),
    //this function does not consider BOMs and possibly differing byte ordering.

    //Sets the string to the printed value of n in the specified base,
    //and returns a reference to the string.
    //The base is 10 by default and must be between 2 and 36.
    //The formatting always uses QLocale::C, i.e., English/UnitedStates.
    //To get a localized string representation of a number,
    //use QLocale::toString() with the appropriate locale.
    QString & setNum(short    n, int base=10)
    { return setNum(qlonglong(n), base); }

    QString & setNum(ushort   n, int base=10)
    { return setNum(qulonglong(n), base); }

    QString & setNum(int      n, int base=10)
    { return setNum(qlonglong(n), base); }

    QString & setNum(uint     n, int base=10)
    { return setNum(qulonglong(n), base); }

    QString & setNum(long     n, int base=10)
    { return setNum(qlonglong(n), base); }

    QString & setNum(ulong    n, int base=10)
    { return setNum(qulonglong(n), base); }

    QString & setNum(qlonglong , int base=10);
    QString & setNum(qulonglong, int base=10);

    QString & setNum(float n, char format='g', int precision=6)
    { return setNum(double(n),format,precision); }

    QString & setNum(double,  char format='g', int precision=6);
    //Sets the string to the printed value of n,
    //formatted according to the given format and precision,
    //and returns a reference to the string.

    //Returns a string equivalent of the number n according to the specified base.
    //The base is 10 by default and must be between 2 and 36.
    //For bases other than 10, n is treated as an unsigned integer.
    //The formatting always uses QLocale::C, i.e., English/UnitedStates.
    //To get a localized string representation of a number,
    //use QLocale::toString() with the appropriate locale.
    static QString number(int         , int base=10);
    static QString number(uint        , int base=10);
    static QString number(long        , int base=10);
    static QString number(ulong       , int base=10);
    static QString number(qlonglong   , int base=10);
    static QString number(qulonglong  , int base=10);
    static QString number(double     n, char format='g', int precision=6);
    //Returns a string representing the floating-point number.
    //Returns a string that represents n,
    //formatted according to the specified format and precision.
    //For formats with an exponent,
    //the exponent will show its sign and have at least two digits,
    //left-padding the exponent with zero if needed.

    void resize(qsizetype size);  //不必要调用
    void resize(qsizetype size, QChar fillChar);

    QString & fill(QChar c, qsizetype size = -1); //本函会修改 本类的大小
    //Sets every character in the string to character c.
    //If size is different from -1 (default),
    //the string is resized to size beforehand.

    void truncate(qsizetype pos); //形参是下标
    //Truncates the string at the given pos index.

    void chop    (qsizetype n)  ; //形参是被裁的数量
    //Removes n characters from the end of the string.
    //If n is greater than or equal to size(), the result is an empty string;
    //if n is negative, it is equivalent to passing zero.

    inline void reserve(qsizetype asize)
    {
        if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin())
            reallocData(qMax(asize, size()), QArrayData::KeepSize);
        if (d->constAllocatedCapacity())
            d->setFlag(Data::CapacityReserved);
    }

    inline void squeeze()
    {
        if (!d.isMutable())
            return;
        if (d->needsDetach() || size() < capacity())
            reallocData(d.size, QArrayData::KeepSize);
        if (d->constAllocatedCapacity())
            d->clearFlag(Data::CapacityReserved);
    }

    //Clears the contents of the string and makes it null.
    void clear() { if (!isNull()) *this = QString(); }


    inline QString & prepend(      QChar            c)
    { return insert(0, c); }

    inline QString & prepend(const QChar         * uc, qsizetype len)
    { return insert(0, uc, len); }

#if QT_STRINGVIEW_LEVEL < 2
    inline QString & prepend(const QString       &  s)
    { return insert(0, s); }
#endif

    QT_ASCII_CAST_WARN
    inline QString & prepend(const char          *  s)
    { return prepend(QString::fromUtf8(s)); }

    QT_ASCII_CAST_WARN
    inline QString & prepend(const QByteArray    &  s)
    { return prepend(QString::fromUtf8(s)); }

    inline QString & prepend(      QStringView      v)
    { return prepend(v.data(), v.length()); }

    inline QString & prepend(      QLatin1String    s)
    { return insert(0, s); }

    //Inserts c at the given index i in the string.
    QString & insert(qsizetype i,       QChar           c); //插入 QChar字符

    QString & insert(qsizetype i, const QChar        * uc, qsizetype len);
    //Inserts the first len characters of the QChar array uc at the
    //given index i in the string.
#if QT_STRINGVIEW_LEVEL < 2
    inline
    QString & insert(qsizetype i, const QString      &  s)
    { return insert(i, s.constData(), s.length()); }
    //Inserts the string s at the given index i and
    //returns a reference to this string.
    //This string grows to accommodate the insertion.
    //If i is beyond the end of the string,
    //space characters are appended to the string to reach this position,
    //followed by s.
#endif

    QT_ASCII_CAST_WARN inline
    QString & insert(qsizetype i, const char         *  s)
    { return insert(i, QString::fromUtf8(s)); }

    QT_ASCII_CAST_WARN inline
    QString & insert(qsizetype i, const QByteArray   &  s)
    { return insert(i, QString::fromUtf8(s)); }

    inline
    QString & insert(qsizetype i,       QStringView     v)
    { return insert(i, v.data(), v.length()); }

    QString & insert(qsizetype i,       QLatin1String   s);

    QString & append(      QChar            c);

    QString & append(const QChar         * uc, qsizetype len);

#if QT_STRINGVIEW_LEVEL < 2
    QString & append(const QString       &  s);
#endif

    QT_ASCII_CAST_WARN inline
    QString & append(const char          *  s)
    { return append(QString::fromUtf8(s)); }

    QT_ASCII_CAST_WARN inline
    QString & append(const QByteArray    &  s)
    { return append(QString::fromUtf8(s)); }

    inline
    QString & append(      QStringView      v)
    { return append(v.data(), v.length()); }

    QString & append(      QLatin1String    s);

    inline QString & operator+=(      QChar           c)
    { return append(c); }

#if QT_STRINGVIEW_LEVEL < 2
    inline QString & operator+=(const QString       & s) { return append(s); }
#endif

    QT_ASCII_CAST_WARN
    inline QString & operator+=(const char          * s)
    { return append(QString::fromUtf8(s)); }

    QT_ASCII_CAST_WARN
    inline QString & operator+=(const QByteArray    & s)
    { return append(QString::fromUtf8(s)); }

    inline QString & operator+=(      QStringView     v) { return append(v); }
    inline QString & operator+=(      QLatin1String   s) { return append(s); }

    //Replaces len characters beginning at index i with the character after and
    //returns a reference to this string.
    QString & replace(qsizetype i, qsizetype len,       QChar     after);

    QString & replace(qsizetype i, qsizetype len, const QChar   * s, qsizetype slen);
    //Replaces len characters beginning at index i with the
    //first slen characters of the QChar array s and returns a
    //reference to this string.

    QString & replace(qsizetype i, qsizetype len, const QString & after);
    //Replaces len characters beginning at index i with the string after and
    //returns a reference to this string.
    //Note: If the specified position i is within the string,
    //but i + len goes outside the strings range,
    //then len will be adjusted to stop at the end of the string.

    //Replaces every occurrence of the character before with the
    //character after and returns a reference to this string.
    //If cs is Qt::CaseSensitive (default),   //替换原字符串里所有的 before字符
    //the search is case sensitive; otherwise the search is case insensitive.
    QString & replace(      QChar   before,       QChar     after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString & replace(      QChar   c     , const QString & after, //多处替换
                     Qt::CaseSensitivity cs = Qt::CaseSensitive);
    //Replaces every occurrence of the character c in the string with after and
    //returns a reference to this string.

    QString & replace(const QChar * before, qsizetype blen ,       //多处替换
                      const QChar * after , qsizetype alen ,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);
    //Replaces each occurrence in this string of the first blen characters of
    //before with the first alen characters of after and returns a
    //reference to this string.

    QString & replace(const QString & before, const QString       & after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive); //多处替换
    //Replaces every occurrence of the string before with the
    //string after and returns a reference to this string.

    QString & replace(const QString & before,       QLatin1String   after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString & replace(QLatin1String   before,       QLatin1String   after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString & replace(QLatin1String   before, const QString       & after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString & replace(QChar           c     ,       QLatin1String   after,
                      Qt::CaseSensitivity cs = Qt::CaseSensitive);

#if QT_CONFIG(regularexpression)
    QString & replace(const QRegularExpression & re, const QString  &after);

    inline
    QString & remove (const QRegularExpression & re)
    { return replace(re, QString()); }
#endif

    template <typename Predicate>
    QString &removeIf(Predicate pred)
    {
        QtPrivate::sequential_erase_if(*this, pred);
        return *this;
    }

    //Removes len characters from the string, starting at the given position i,
    //and returns a reference to the string.
    //If the specified position i is within the string, but i + len is beyond the
    //end of the string, the string is truncated at the specified position.
    //Element removal will preserve the string's capacity and not reduce the
    //amount of allocated memory.
    //To shed extra capacity and free as much memory as possible,
    //call squeeze() after the last change to the string's size.
    QString & remove(      qsizetype       i,     qsizetype len);

    //Removes every occurrence of the character c in this string,
    //and returns a reference to this string.
    //If cs is Qt::CaseSensitive (default), the search is case sensitive;
    //otherwise the search is case insensitive.
    QString & remove(      QChar           c,
                     Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString & remove(const QString       & s,
                     Qt::CaseSensitivity cs = Qt::CaseSensitive);
    //Removes every occurrence of the given s string in this string,
    //and returns a reference to this string.

    QString & remove(      QLatin1String   s,
                     Qt::CaseSensitivity cs = Qt::CaseSensitive);

    // ASCII compatibility
#if defined(QT_RESTRICTED_CAST_FROM_ASCII) //一般是不会做出限制的
    template <qsizetype N>
    inline
    QString(const char (&ch)[N])  : QString(fromUtf8(ch)) {}

    template <qsizetype N>
    QString(char (&)[N]) = delete;

    template <qsizetype N>
    inline
    QString & operator=(const char (&ch)[N])
    { return (*this = fromUtf8(ch, N - 1)); }

    template <qsizetype N>
    QString & operator=(char (&)[N]) = delete;
#endif

#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
    //一般是不会做出限制的。这个条件编译 #if 里的内容很重要,拆分到归类后的地方了。
    //包括构造函数、 =赋值运算符函数、追加删除插入 ascii字符、以及比较运算符 == != < > 等
    //全拆走了,详情见官方源代码。

    // these are needed, so it compiles with STL support enabled
#endif

    //以下是模仿 STL容器的通用成员函数样式
    typedef       QChar *       iterator;
    typedef                     iterator Iterator;

    typedef const QChar * const_iterator;
    typedef               const_iterator ConstIterator;

    typedef std::reverse_iterator<      iterator>       reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

    inline       iterator      begin()
    { detach(); return reinterpret_cast<QChar*>(d.data()); }

    inline const_iterator      begin() const
    { return reinterpret_cast<const QChar*>(d.data()); }

    inline const_iterator     cbegin() const
    { return reinterpret_cast<const QChar*>(d.data()); }

    inline const_iterator constBegin() const
    { return reinterpret_cast<const QChar*>(d.data()); }

    inline       iterator      end()
    { detach(); return reinterpret_cast<QChar*>(d.data() + d.size); }

    inline const_iterator      end() const
    { return reinterpret_cast<const QChar*>(d.data() + d.size); }

    inline const_iterator     cend() const
    { return reinterpret_cast<const QChar*>(d.data() + d.size); }

    inline const_iterator constEnd() const
    { return reinterpret_cast<const QChar*>(d.data() + d.size); }

          reverse_iterator  rbegin()       { return       reverse_iterator(end()); }
    const_reverse_iterator  rbegin() const { return const_reverse_iterator(end()); }
    const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }

          reverse_iterator  rend()       { return       reverse_iterator(begin()); }
    const_reverse_iterator  rend() const { return const_reverse_iterator(begin()); }
    const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }

    // STL compatibility  其实迭代器指向的容器,会因为容器重新分配而失效的。
    //using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
    typedef qsizetype size_type;
    typedef qptrdiff  difference_type;
    //typedef QIntegerForSizeof<void *>::Signed qptrdiff;

    typedef       QChar &       reference;
    typedef const QChar & const_reference;

    typedef       QChar        value_type;
    typedef       QChar *         pointer;
    typedef const QChar *   const_pointer;

    inline void push_back (      QChar     c) { append (c); }
    inline void push_back (const QString & s) { append (s); }
    inline void push_front(      QChar     c) { prepend(c); }
    inline void push_front(const QString & s) { prepend(s); }

    void shrink_to_fit() { squeeze(); }

    iterator erase(const_iterator first, const_iterator last);


#if defined(Q_OS_DARWIN) || defined(Q_QDOC)  //这个没有用
    static QString fromCFString(CFStringRef string);

    CFStringRef toCFString() const Q_DECL_CF_RETURNS_RETAINED;

    static QString fromNSString(const NSString *string);

    NSString *toNSString() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif


}; //完结 class QString。撒花!!后面还有几个有用的函数,要附带上+++++++


#if !defined(QT_USE_FAST_OPERATOR_PLUS) && !defined(QT_USE_QSTRINGBUILDER)

inline const
QString operator+(const  QString   & s1, const QString   & s2)
{   QString t(s1); t += s2; return t; }

inline const
QString operator+(const  QString   & s1,       QChar       s2)
{   QString t(s1); t += s2; return t; }

inline const
QString operator+(       QChar       s1, const QString   & s2)
{   QString t(s1); t += s2; return t; }

#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)

QT_ASCII_CAST_WARN
inline const
QString operator+(const  QString   & s1, const char      * s2)
{   QString t(s1); t += QString::fromUtf8(s2); return t; }

QT_ASCII_CAST_WARN
inline const
QString operator+(const char       * s1, const QString    & s2)
{   QString t = QString::fromUtf8(s1); t += s2; return t; }

QT_ASCII_CAST_WARN inline const
QString operator+(const QByteArray & ba, const QString    &  s)
{   QString t = QString::fromUtf8(ba); t += s; return t; }

QT_ASCII_CAST_WARN inline const
QString operator+(const QString    &  s, const QByteArray & ba)
{   QString t(s); t += QString::fromUtf8(ba); return t; }

#  endif // QT_NO_CAST_FROM_ASCII
#endif // QT_USE_QSTRINGBUILDER


#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT QDataStream & operator<<(QDataStream &, const QString &);
Q_CORE_EXPORT QDataStream & operator>>(QDataStream &,       QString &);
#endif  //至此是让 <<、 >> 运算符支持 QString 类型

(10)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值