从Qt中的QJsonArray构造QString [英] Construct QString from QJsonArray in Qt

查看:260
本文介绍了从Qt中的QJsonArray构造QString的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试从 QJsonArray 的值构造 QString 时,出现以下错误:



错误:将'const QString'传递为'this'参数将丢弃限定符[-fpermissive]



Dunno在此代码中我弄错了:

  QString< CLASS_NAME> :: getData(QString callerValue){
QString BASE_URL =< URL>;

QString stringToReturn =;
QObject :: connect(manager,& QNetworkAccessManager :: finished,this,[=](QNetworkReply * reply){
QByteArray barr = reply-> readAll();
QJsonParseError jpe ;
QJsonDocument jdoc = QJsonDocument :: fromJson(barr& jpe);
QJsonArray近奇数组= jdoc.array();
foreach(const QJsonValue&jv,onymoussArray){
QJsonObject jo = jv.toObject();
QString s = jo.value(< VALUE>)。toString();
stringToReturn.append(s +,); / *错误:上面的错误来自此行... * /
}
}
);
request.setUrl(QUrl(BASE_URL + callerValue));
manager-> get(request);
return stringToReturn;
}


解决方案

这是另一个经典的希望世界是同步的问题。您不能那样编码。 getData 方法无法按照您希望的方式编写。 getData 这样会阻塞,这很浪费并且会导致有趣的问题-并非最后一个是可怕的用户体验。



取决于您的应用程序,将有几种可能的修复方法:


  1. redo getData 使用协程和 co_yield 的隐式连续传递样式-这是未来,并且只能在最新的编译器上完成,除非您使用诸如此类的技巧


  2. redo getData 采用显式连续传递样式,

  3. >
  4. 重做 getData 并在数据可用时发出通知,


  5. 具有一个处理代码进度的显式状态机。


连续传递样式需要最少的变化。还要注意其他修复程序-最值得注意的是,您不应该使用 QNetworkAccessManager 的信号:您只对此查询的结果感兴趣,而不对每个查询感兴趣!捕获 QNetworkAccessManager :: finished 信号仅在您确实有一个中心点可以处理所有或至少最频繁的请求时才有用。在这种情况下,这是一个明智的优化:将第一个连接添加到无连接器的Hiterto对象上会产生几个 malloc 的开销。

  void类:: getData(const QString& urlSuffix,std :: function< void(const QString&)> cont){
自动const urlString = QStringLiteral( URL%1)。arg(urlSuffix);
QNetworkRequest请求(QUrl(urlString));
auto * reply = m_manager.get(请求);
QObject :: connect(reply,& QNetworkReply :: finished,this,[=] {
QString result;
auto data = reply-> readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument :: fromJson(data,& jpe);
auto const同义词= jdoc.array();
用于(auto& value:同义词){
auto object = value.toObject();
auto s = object.value(< VALUE>)。toString();
if(!result.isEmpty())
result.append(QLatin1String(,))
result.append(s);
}
reply-> deleteLater();
cont(结果);
});
}

惰性样式要求使用 getData 可重新启动,并允许连续传递,只要将延续连接到信号即可:

  class Class:public QObject {
Q_OBJECT
QString m_cachedData;
QNetworkAccessManager m_manager {this};
Q_SIGNAL void dataAvailable(const QString&);
...
};

QString类:: getData(const QString& urlSuffix){
if(!m_cachedData.isEmpty())
return m_cachedData;

auto const urlString = QStringLiteral( URL%1)。arg(urlSuffix);
QNetworkRequest请求(QUrl(urlString));
auto * reply = m_manager.get(请求);
QObject :: connect(reply,& QNetworkReply :: finished,this,[=] {
m_cachedData.clear();
auto data = reply-> readAll();
QJsonParseError jpe;
自动jdoc = QJsonDocument :: fromJson(data,& jpe);
自动const同义词= jdoc.array();
for(auto& value:同义词){
auto object = value.toObject();
auto s = object.value(< VALUE>)。toString();
if(!m_cachedData.isEmpty ())
m_cachedData.append(QLatin1String(,))
m_cachedData.append(s);
}
reply-> deleteLater();
发出dataAvailable(m_cachedData);
});
return {};
}

状态机将状态转换形式化:

  class类:公共QObject {
Q_OBJECT
QStateMachine m_sm {this};
QNetworkAccessManager m_manager {this};
QPointer< QNetworkReply> m_reply;
QState s_idle {& m_sm},s_busy {& m_sm},s_done {& m_sm};
Q_SIGNAL void to_busy();
void getData(const QString&);
...

};

Class :: Class(QObject * parent):QObject(parent){
m_sm.setInitialState(& s_idle);
s_idle.addTransition(this,& Class :: to_busy,& s_busy);
s_done.addTransition(& s_idle);
m_sm.start();
}

void Class :: getData(const QString& urlSuffix){
static char const kInit [] =已初始化;
auto const urlString = QStringLiteral( URL%1)。arg(urlSuffix);
QNetworkRequest请求(QUrl(urlString));
m_reply = m_manager.get(请求);
s_busy.addTransition(reply,& QNetworkReply :: finished,& s_done);
to_busy();
if(!s_done.property(kInit).toBool()){
QObject :: connect(& s_done,& QState :: entered,this,[=] {
QString结果;
自动数据= m_reply-> readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument :: fromJson(data,& jpe);
auto const同义词= jdoc.array();
表示(自动和值:同义词){
自动对象= value.toObject();
自动s = object.value(< VALUE >)。toString();
if(!result.isEmpty())
result.append(QLatin1String(,))
result.append(s);
}
m_reply-> deleteLater();
});
s_done.setProperty(kInit,true);
}
}


While trying to construct a QString from values from a QJsonArray, I get the following error:

error: passing 'const QString' as 'this' argument discards qualifiers [-fpermissive].

Dunno where I am getting it wrong in this code:

QString <CLASS_NAME>::getData(QString callerValue) {
    QString BASE_URL = "<URL>";

    QString stringToReturn = "";
    QObject::connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
      QByteArray barr = reply->readAll();
      QJsonParseError jpe;
      QJsonDocument jdoc = QJsonDocument::fromJson(barr, &jpe);
      QJsonArray synonymsArray = jdoc.array();
      foreach (const QJsonValue &jv, synonymsArray) {
        QJsonObject jo = jv.toObject();
        QString s = jo.value("<VALUE>").toString();
        stringToReturn.append(s + ", "); /* ERROR: The error above is from this line... */
      }
    }
    );
    request.setUrl(QUrl(BASE_URL + callerValue));
    manager->get(request);
    return stringToReturn;
  }

解决方案

This is another classic "I wish the world was synchronous" problem. You can't code that way. The getData method can't be written the way you want it to be. getData done that way would block, and that's quite wasteful and can lead to interesting problems - not the last of which is horrible UX.

Depending on your application, there would be several possible fixes:

  1. redo getData in implicit continuation-passing style using coroutines and co_yield - this is the future and can be done only on the most recent compilers unless you use hacks such boost coroutines.

  2. redo getData in explicit continuation-passing style,

  3. redo getData in lazy style with notification when data is available,

  4. have an explicit state machine that deals with progress of your code.

The continuation-passing style requires the least changes. Note the other fixes too - most notably that you shouldn't be using the QNetworkAccessManager's signals: you're interested only in results to this one query, not every query! Catching QNetworkAccessManager::finished signal is only useful if you truly have a central point where all or at least most frequent requests can be handled. In such a case, it's a sensible optimization: there is overhead of several mallocs to adding the first connection to a hiterto connection-free object.

void Class::getData(const QString &urlSuffix, std::function<void(const QString &)> cont) {
  auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
  QNetworkRequest request(QUrl(urlString));
  auto *reply = m_manager.get(request);
  QObject::connect(reply, &QNetworkReply::finished, this, [=]{
    QString result;
    auto data = reply->readAll();
    QJsonParseError jpe;
    auto jdoc = QJsonDocument::fromJson(data, &jpe);
    auto const synonyms = jdoc.array();
    for (auto &value : synonyms) {
      auto object = value.toObject();
      auto s = object.value("<VALUE">).toString();
      if (!result.isEmpty())
        result.append(QLatin1String(", "))
      result.append(s);
    }
    reply->deleteLater();
    cont(result);
  });
}

The lazy style requires the code that uses getData to be restartable, and allows continuation-passing as well, as long as the continuation is connected to the signal:

class Class : public QObject {
  Q_OBJECT
  QString m_cachedData;
  QNetworkAccessManager m_manager{this};
  Q_SIGNAL void dataAvailable(const QString &);
  ...
};

QString Class::getData(const QString &urlSuffix) {
  if (!m_cachedData.isEmpty())
    return m_cachedData;

  auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
  QNetworkRequest request(QUrl(urlString));
  auto *reply = m_manager.get(request);
  QObject::connect(reply, &QNetworkReply::finished, this, [=]{
    m_cachedData.clear();
    auto data = reply->readAll();
    QJsonParseError jpe;
    auto jdoc = QJsonDocument::fromJson(data, &jpe);
    auto const synonyms = jdoc.array();
    for (auto &value : synonyms) {
      auto object = value.toObject();
      auto s = object.value("<VALUE">).toString();
      if (!m_cachedData.isEmpty())
        m_cachedData.append(QLatin1String(", "))
      m_cachedData.append(s);
    }
    reply->deleteLater();
    emit dataAvailable(m_cachedData);
  });
  return {};
}

The state machine formalizes the state progression:

class Class : public QObject {
  Q_OBJECT
  QStateMachine m_sm{this};
  QNetworkAccessManager m_manager{this};
  QPointer<QNetworkReply> m_reply;
  QState s_idle{&m_sm}, s_busy{&m_sm}, s_done{&m_sm};
  Q_SIGNAL void to_busy();
  void getData(const QString &);
  ...

};

Class::Class(QObject * parent) : QObject(parent) {
  m_sm.setInitialState(&s_idle);
  s_idle.addTransition(this, &Class::to_busy, &s_busy);
  s_done.addTransition(&s_idle);
  m_sm.start();
}

void Class::getData(const QString &urlSuffix) {
  static char const kInit[] = "initialized";
  auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
  QNetworkRequest request(QUrl(urlString));
  m_reply = m_manager.get(request);
  s_busy.addTransition(reply, &QNetworkReply::finished, &s_done);
  to_busy();
  if (!s_done.property(kInit).toBool()) {
    QObject::connect(&s_done, &QState::entered, this, [=]{
      QString result;
      auto data = m_reply->readAll();
      QJsonParseError jpe;
      auto jdoc = QJsonDocument::fromJson(data, &jpe);
      auto const synonyms = jdoc.array();
      for (auto &value : synonyms) {
        auto object = value.toObject();
        auto s = object.value("<VALUE">).toString();
        if (!result.isEmpty())
          result.append(QLatin1String(", "))
        result.append(s);
      }
      m_reply->deleteLater();
    });
    s_done.setProperty(kInit, true);
  }
}

这篇关于从Qt中的QJsonArray构造QString的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆