草庐IT

c++ - 暂停时的快速高斯模糊

coder 2024-01-30 原文

关闭。这个问题需要debugging details .它目前不接受答案。












想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。

3年前关闭。




Improve this question




cocos2d-x 我需要实现快速高斯模糊,它应该是这样的(我刚刚在 App Store 上找到了一些已经完成这种模糊的游戏,统一):



所以,很好淡入 - 淡出当用户暂停游戏时模糊。

GPUImage 已经有我需要的快速模糊,但我找不到 cocos2d-x 的解决方案。

  • v1 code when it was (GPUImage v1)客观的
    C
  • v2 code when is now Swift(GPUImage v2) swift
  • GPUImage-x C++版

  • Here is result of live camera view using GPUImage2 - 在 iPod Touch 5G 上进行了测试,在这个缓慢而旧的设备上运行速度很快。

    即使在 iPod Touch 5G 等非常慢的设备上,GPUImage 中的模糊也能非常快地工作。
    为 cocos2d-x 寻找具有超快速高斯模糊的解决方案。

    最佳答案

    学习后"Post-Processing Effects in Cocos2d-X""RENDERTEXTURE + BLUR" ,我想到了以下解决方案。

    在 Cocos2s-X 中实现后期处理效果的常用方法是实现图层。场景是一层,后处理是另一层,它使用场景层作为输入。使用这种技术,后期处理可以操纵渲染的场景。

    模糊算法在着色器中实现。在场景上应用模糊效果的一种常见方法是首先沿视口(viewport)的 X 轴进行模糊处理,然后沿视口(viewport)的 Y 轴进行第二次模糊处理(参见 ShaderLesson5)。这是一个可以接受的近似值,它提供了巨大的性能增益。

    这意味着,我们在 Cocos2s-X 中需要 2 个后期处理层。所以我们需要 3 层,一层用于场景,2 层用于后期处理:

    // scene (game) layer
    m_gameLayer = Layer::create();
    this->addChild(m_gameLayer, 0);
    
    // blur X layer
    m_blurX_PostProcessLayer = PostProcess::create("shader/blur.vert", "shader/blur.frag");
    m_blurX_PostProcessLayer->setAnchorPoint(Point::ZERO);
    m_blurX_PostProcessLayer->setPosition(Point::ZERO);
    this->addChild(m_blurX_PostProcessLayer, 1);
    
    // blur y layer
    m_blurY_PostProcessLayer = PostProcess::create("shader/blur.vert", "shader/blur.frag");
    m_blurY_PostProcessLayer->setAnchorPoint(Point::ZERO);
    m_blurY_PostProcessLayer->setPosition(Point::ZERO);
    this->addChild(m_blurY_PostProcessLayer, 2);
    

    注意,场景的 Sprite 和资源必须添加到m_gameLayer .

    updated方法,后期处理必须应用到场景中(稍后我将描述制服的设置):
    // blur in X direction
    
    cocos2d::GLProgramState &blurXstate = m_blurX_PostProcessLayer->ProgramState();
    blurXstate.setUniformVec2( "u_blurOffset", Vec2( 1.0f/visibleSize.width, 0.0 ) ); 
    blurXstate.setUniformFloat( "u_blurStrength", (float)blurStrength );
    
    m_blurX_PostProcessLayer->draw(m_gameLayer);
    
    // blur in Y direction
    
    cocos2d::GLProgramState &blurYstate = m_blurY_PostProcessLayer->ProgramState();
    blurYstate.setUniformVec2( "u_blurOffset", Vec2( 0.0, 1.0f/visibleSize.height ) );
    blurYstate.setUniformFloat( "u_blurStrength", (float)blurStrength );
    
    m_blurY_PostProcessLayer->draw(m_blurX_PostProcessLayer);
    

    为了管理后期流程,我实现了一个类 PostProcess ,我试图让事情尽可能简单:

    后处理.hpp
    #include <string>
    #include "cocos2d.h"
    
    class PostProcess : public cocos2d::Layer
    {
    private:
        PostProcess(void) {}
        virtual ~PostProcess() {}
    public:
        static PostProcess* create(const std::string& vertexShaderFile, const std::string& fragmentShaderFile);
        virtual bool init(const std::string& vertexShaderFile, const std::string& fragmentShaderFile);
        void draw(cocos2d::Layer* layer);
        cocos2d::GLProgram      & Program( void )      { return *_program; }
        cocos2d::GLProgramState & ProgramState( void ) { return *_progState; }
    private:
        cocos2d::GLProgram       *_program;
        cocos2d::GLProgramState  *_progState;
        cocos2d::RenderTexture   *_renderTexture;
        cocos2d::Sprite          *_sprite;
    };
    

    后处理.cpp
    #include "PostProcess.hpp"
    
    using namespace cocos2d;
    
    bool PostProcess::init(const std::string& vertexShaderFile, const std::string& fragmentShaderFile)
    {
        if (!Layer::init()) {
            return false;
        }
    
        _program = GLProgram::createWithFilenames(vertexShaderFile, fragmentShaderFile);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_POSITION);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_COLOR);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT, GLProgram::VERTEX_ATTRIB_BLEND_WEIGHT);
        _program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX, GLProgram::VERTEX_ATTRIB_BLEND_INDEX);
        _program->link();
    
        _progState = GLProgramState::getOrCreateWithGLProgram(_program);
    
        _program->updateUniforms();
    
        auto visibleSize = Director::getInstance()->getVisibleSize();
    
        _renderTexture = RenderTexture::create(visibleSize.width, visibleSize.height);
        _renderTexture->retain();
    
        _sprite = Sprite::createWithTexture(_renderTexture->getSprite()->getTexture());
        _sprite->setTextureRect(Rect(0, 0, _sprite->getTexture()->getContentSize().width,
        _sprite->getTexture()->getContentSize().height));
        _sprite->setAnchorPoint(Point::ZERO);
        _sprite->setPosition(Point::ZERO);
        _sprite->setFlippedY(true);
        _sprite->setGLProgram(_program);
        _sprite->setGLProgramState(_progState);
        this->addChild(_sprite);
    
        return true;
    }
    
    void PostProcess::draw(cocos2d::Layer* layer)
    {
        _renderTexture->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
        layer->visit();
        _renderTexture->end();
    }
    
    PostProcess* PostProcess::create(const std::string& vertexShaderFile, const std::string& fragmentShaderFile)
    {
        auto p = new (std::nothrow) PostProcess();
        if (p && p->init(vertexShaderFile, fragmentShaderFile)) {
            p->autorelease();
            return p;
        }
        delete p;
        return nullptr;
    }
    

    着色器需要一个包含模糊算法偏移量的 unifor ( u_blurOffset )。这是第一次模糊 channel 沿 X 轴的 2 个像素之间的距离,以及第二次模糊 channel 沿 Y 轴的 2 个纹素之间的距离。
    模糊效果的强度由统一变量 ( u_blurStrength ) 设置。其中 0.0 表示关闭模糊,1.0 表示最大模糊。最大模糊效果由 MAX_BLUR_WIDHT 的值定义,它定义了在每个方向上查看的纹素范围。所以这或多或少是模糊半径。如果增加该值,模糊效果会增加,但会损失性能。如果您降低该值,模糊效果会降低,但您将赢得性能。性能与MAX_BLUR_WIDHT值的关系值得庆幸的是,由于近似的 2 pass 实现,它是线性的(而不是二次的)。
    我决定避免预先计算高斯权重并将它们传递给着色器(高斯权重取决于 MAX_BLUR_WIDHTu_blurStrength )。相反,我使用了平滑的 Hermite interpolation类似于 GLSL 函数 smoothstep :

    模糊.vert
    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    attribute vec4 a_color;
    
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    
    void main()
    {
        gl_Position     = CC_MVPMatrix * a_position;
        v_fragmentColor = a_color;
        v_texCoord      = a_texCoord;
    }
    

    模糊片段
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    
    uniform vec2  u_blurOffset;
    uniform float u_blurStrength;
    
    #define MAX_BLUR_WIDHT 10
    
    void main()
    {
        vec4 color   = texture2D(CC_Texture0, v_texCoord);
    
        float blurWidth = u_blurStrength * float(MAX_BLUR_WIDHT);
        vec4 blurColor  = vec4(color.rgb, 1.0);
        for (int i = 1; i <= MAX_BLUR_WIDHT; ++ i)
        {
            if ( float(i) >= blurWidth )
                break;
    
            float weight = 1.0 - float(i) / blurWidth;
            weight = weight * weight * (3.0 - 2.0 * weight); // smoothstep
    
            vec4 sampleColor1 = texture2D(CC_Texture0, v_texCoord + u_blurOffset * float(i));
            vec4 sampleColor2 = texture2D(CC_Texture0, v_texCoord - u_blurOffset * float(i));
            blurColor += vec4(sampleColor1.rgb + sampleColor2.rgb, 2.0) * weight; 
        }
    
        gl_FragColor = vec4(blurColor.rgb / blurColor.w, color.a);
    }
    

    完整的 C++ 和 GLSL 源代码可以在 GitHub 上找到。 (该实现可以通过 bool HelloWorld::m_blurFast = false 激活)。

    看预览:

    每个模糊半径的单独着色器

    高斯模糊算法的高性能版本是 GPUImage-x 中提出的解决方案。 .在这个实现中,为每个模糊半径创建了一个单独的模糊着色器。完整的 cocos2d-x 演示实现的源代码可以在 GitHub 中找到。 .实现提供2个变体,标准实现和优化实现,如链接中的实现,可以通过bool GPUimageBlur::m_optimized设置.该实现为从 0 到 int GPUimageBlur::m_maxRadius 的每个半径生成一个着色器。和一个西格玛float GPUimageBlur::m_sigma .

    看预览:

    快速有限质量模糊

    一个更强大的解决方案,但具有 明显极低质量 , 将使用 Optimizing Gaussian blurs on a mobile GPU 中提供的着色器.模糊不是动态的,只能打开或关闭:
    update方法:
    // blur pass 1
    cocos2d::GLProgramState &blurPass1state = m_blurPass1_PostProcessLayer->ProgramState();
    blurPass1state.setUniformVec2( "u_blurOffset", Vec2( blurStrength/visibleSize.width, blurStrength/visibleSize.height ) );
    m_gameLayer->setVisible( true );
    m_blurPass1_PostProcessLayer->draw(m_gameLayer);
    m_gameLayer->setVisible( false );
    
    // blur pass 2
    cocos2d::GLProgramState &blurPass2state = m_blurPass2_PostProcessLayer->ProgramState();
    blurPass2state.setUniformVec2( "u_blurOffset", Vec2( blurStrength/visibleSize.width, -blurStrength/visibleSize.height ) );
    m_blurPass1_PostProcessLayer->setVisible( true );
    m_blurPass2_PostProcessLayer->draw(m_blurPass1_PostProcessLayer);
    m_blurPass1_PostProcessLayer->setVisible( false );
    

    Vetex着色器:
    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    
    varying vec2 blurCoordinates[5];
    
    uniform vec2  u_blurOffset;
    
    void main()
    {
        gl_Position     = CC_MVPMatrix * a_position;
    
        blurCoordinates[0] = a_texCoord.xy;
        blurCoordinates[1] = a_texCoord.xy + u_blurOffset * 1.407333;
        blurCoordinates[2] = a_texCoord.xy - u_blurOffset * 1.407333;
        blurCoordinates[3] = a_texCoord.xy + u_blurOffset * 3.294215;
        blurCoordinates[4] = a_texCoord.xy - u_blurOffset * 3.294215;
    }
    

    片段着色器
    varying vec2 blurCoordinates[5];
    
    uniform float u_blurStrength;
    
    void main()
    {
        vec4 sum = vec4(0.0);
        sum += texture2D(CC_Texture0, blurCoordinates[0]) * 0.204164;
        sum += texture2D(CC_Texture0, blurCoordinates[1]) * 0.304005;
        sum += texture2D(CC_Texture0, blurCoordinates[2]) * 0.304005;
        sum += texture2D(CC_Texture0, blurCoordinates[3]) * 0.093913;
        sum += texture2D(CC_Texture0, blurCoordinates[4]) * 0.093913;
        gl_FragColor = sum;
    }
    

    看预览:

    完整的 C++ 和 GLSL 源代码可以在 GitHub 上找到。 (实现可以通过 bool HelloWorld::m_blurFast 切换)。

    具有两层的渐进式解决方案(帧缓冲区)

    该解决方案的想法是对场景进行平滑、渐进、高质量的模糊处理。为此,需要一个弱但快速且高质量的模糊算法。模糊 Sprite 不会被删除,它将被存储以供下次刷新游戏引擎时使用,并用作下一个模糊步骤的源。这意味着弱模糊 Sprite 再次变得模糊,因此它比上一个更模糊。这是一个渐进的过程,以强大而精确的模糊 Sprite 结束。
    要设置此过程,需要 3 个层,即游戏层和 2 个模糊层(偶数和奇数)。
    m_gameLayer = Layer::create();
    m_gameLayer->setVisible( false );
    this->addChild(m_gameLayer, 0);
    
    // blur layer even
    m_blur_PostProcessLayerEven = PostProcess::create("shader/blur_fast2.vert", "shader/blur_fast2.frag");
    m_blur_PostProcessLayerEven->setVisible( false );
    m_blur_PostProcessLayerEven->setAnchorPoint(Point::ZERO);
    m_blur_PostProcessLayerEven->setPosition(Point::ZERO);
    this->addChild(m_blur_PostProcessLayerEven, 1);
    
    // blur layer odd
    m_blur_PostProcessLayerOdd = PostProcess::create("shader/blur_fast2.vert", "shader/blur_fast2.frag");
    m_blur_PostProcessLayerOdd->setVisible( false );
    m_blur_PostProcessLayerOdd->setAnchorPoint(Point::ZERO);
    m_blur_PostProcessLayerOdd->setPosition(Point::ZERO);
    this->addChild(m_blur_PostProcessLayerOdd, 1);
    

    请注意,最初所有 3 层都是不可见的。

    在 update` 方法中,一层设置为状态可见。如果没有模糊,那么游戏层是可见的。一旦开始模糊,游戏层就会渲染到偶数层,使用模糊着色器。游戏层变为不可见,偶数层变为可见。在下一个循环中,偶数层被渲染到奇数层,使用模糊着色器。偶数层变为不可见,奇数层变为可见。这个过程一直持续到模糊停止。同时,场景变得越来越模糊,质量越来越高。
    如果必须再次显示原始场景,则游戏层已设置为可见,偶数和奇数层必须设置为不可见。
    update方法:
    bool even = (m_blurTick % 2) == 0;
    if ( m_blur )
    {
        cocos2d::GLProgramState &blurFaststate1 = m_blur_PostProcessLayerEven->ProgramState();
        blurFaststate1.setUniformVec2( "u_texelOffset", Vec2( 1.0f/visibleSize.width, 1.0f/visibleSize.height ) );
        cocos2d::GLProgramState &blurFaststate2 = m_blur_PostProcessLayerOdd->ProgramState();
        blurFaststate2.setUniformVec2( "u_texelOffset", Vec2( -1.0f/visibleSize.width, -1.0f/visibleSize.height ) );
    
        if ( m_blurTick == 0 )
        {
            m_gameLayer->setVisible( true );
            m_blur_PostProcessLayerEven->draw(m_gameLayer);
        }
        else if ( even )
        {
          m_blur_PostProcessLayerEven->draw(m_blur_PostProcessLayerOdd);
        }
        else
        {
          m_blur_PostProcessLayerOdd->draw(m_blur_PostProcessLayerEven);
        }
        ++m_blurTick;
    }
    else
      m_blurTick = 0; 
    
    m_gameLayer->setVisible( !m_blur );
    m_blur_PostProcessLayerEven->setVisible( m_blur && even );
    m_blur_PostProcessLayerOdd->setVisible( m_blur && !even );
    

    着色器是一个简单而精确的 3*3 模糊着色器:

    Vetex着色器:
    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    
    varying vec2 blurCoordinates[9];
    
    uniform vec2 u_texelOffset;
    
    void main()
    {
        gl_Position     = CC_MVPMatrix * a_position;
    
        blurCoordinates[0] = a_texCoord.st + vec2( 0.0,  0.0) * u_texelOffset.st;
        blurCoordinates[1] = a_texCoord.st + vec2(+1.0,  0.0) * u_texelOffset.st;
        blurCoordinates[2] = a_texCoord.st + vec2(-1.0,  0.0) * u_texelOffset.st;
        blurCoordinates[3] = a_texCoord.st + vec2( 0.0, +1.0) * u_texelOffset.st;
        blurCoordinates[4] = a_texCoord.st + vec2( 0.0, -1.0) * u_texelOffset.st;
        blurCoordinates[5] = a_texCoord.st + vec2(-1.0, -1.0) * u_texelOffset.st;
        blurCoordinates[6] = a_texCoord.st + vec2(+1.0, -1.0) * u_texelOffset.st;
        blurCoordinates[7] = a_texCoord.st + vec2(-1.0, +1.0) * u_texelOffset.st;
        blurCoordinates[8] = a_texCoord.st + vec2(+1.0, +1.0) * u_texelOffset.st;
    }
    

    片段着色器:
    varying vec2 blurCoordinates[9];
    
    void main()
    {
        vec4 sum = vec4(0.0);
        sum += texture2D(CC_Texture0, blurCoordinates[0]) * 4.0;
        sum += texture2D(CC_Texture0, blurCoordinates[1]) * 2.0;
        sum += texture2D(CC_Texture0, blurCoordinates[2]) * 2.0;
        sum += texture2D(CC_Texture0, blurCoordinates[3]) * 2.0;
        sum += texture2D(CC_Texture0, blurCoordinates[4]) * 2.0;
        sum += texture2D(CC_Texture0, blurCoordinates[5]) * 1.0;
        sum += texture2D(CC_Texture0, blurCoordinates[6]) * 1.0;
        sum += texture2D(CC_Texture0, blurCoordinates[7]) * 1.0;
        sum += texture2D(CC_Texture0, blurCoordinates[8]) * 1.0;
        sum /= 16.0; 
        gl_FragColor = sum;
    }
    

    同样,完整的 C++ 和 GLSL 源代码可以在 GitHub 上找到。 .

    看预览:

    关于c++ - 暂停时的快速高斯模糊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46745199/

    有关c++ - 暂停时的快速高斯模糊的更多相关文章

    1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    2. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    3. ruby-on-rails - 如何从过时的 TZInfo 标识符中获取 Rails TimeZone 名称? - 2

      已经有一个问题回答了如何将“America/Los_Angeles”转换为“PacificTime(US&Canada)”。但是我想将“美国/太平洋”和其他过时的时区转换为RailsTimeZone。我无法在图书馆中找到任何可以帮助我完成此任务的东西。 最佳答案 来自RailsActiveSupport::TimeZonedocs:TheversionofTZInfobundledwithActiveSupportonlyincludesthedefinitionsnecessarytosupportthezonesdefinedb

    4. ruby - 如何计算 Liquid 中的变量 +1 - 2

      我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

    5. ruby-on-rails - Rails 3 - 过滤器链暂停为 :authentication rendered or redirected - 2

      我仍然收到标题中的“错误”消息,但不知道如何解决。在ApplicationController中,classApplicationController在routes.rb#match'set_activity_account/:id/:value'=>'users#account_activity',:as=>:set_activity_account--thisdoesn'tworkaswell..resources:usersdomemberdoget:action_a,:action_bendcollectiondoget'account_activity'endend和User

    6. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    7. += 的 Ruby 方法 - 2

      有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

    8. ruby - 如何以表格格式快速打印 Ruby 哈希值? - 2

      有没有办法快速将表格格式的ruby​​哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:

    9. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

      出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

    10. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

      我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

    随机推荐