首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >温故而知新—MeasureSpec在View测量中的作用

温故而知新—MeasureSpec在View测量中的作用

作者头像
码上积木
发布于 2021-04-30 03:00:43
发布于 2021-04-30 03:00:43
1.1K00
代码可运行
举报
文章被收录于专栏:码上积木码上积木
运行总次数:0
代码可运行
前言

对于MeasureSpec,你的认识有多少呢?

  • MeasureSpec是干嘛的?存在的意义在哪?
  • MeasureSpec中的mode和size到底指的是什么?
  • MeasureSpec是怎么计算的,与哪些因素有关?
  • 父View测量好子View的MeasureSpec之后,子View会怎么处理?
  • View/ViewGroup、DecorViewMeasureSpec有什么区别?
  • UNSPECIFIED这个特殊模式又有什么用呢?

介绍

首先,我们看下这个类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static class MeasureSpec {
        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

        //00后面跟30个0
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;
        //01后面跟30个0
        public static final int EXACTLY     = 1 << MODE_SHIFT;
        //10后面跟30个0
        public static final int AT_MOST     = 2 << MODE_SHIFT;

        public static int makeMeasureSpec(int size, int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }

        //获取mode
        public static int getMode(int measureSpec) {
            //保留高2位,剩下30个0
            return (measureSpec & MODE_MASK);
        }

        //获取size
        public static int getSize(int measureSpec) {
         //替换高两位00,保留低30位
            return (measureSpec & ~MODE_MASK);
        }

    }

我留下了比较重要的三个方法:

  • makeMeasureSpec。用于生成一个MeasureSpec,生成的方式就是size+mode,得到一个32位的int值。
  • 获取mode。也就是取前2位的值作为mode。
  • 获取size。也就是取后30位的值作为size。

至此,我们至少知道了MeasureSpec是一个32位的int值,高2位为mode(测量模式),低30位为size(测量大小)。

这么做的目的主要是避免过多的对象内存分配。

所以我们可以大致猜测,这个MeasureSpec就是用来标记View的测量参数,其中测量模式可能和View具体怎么显示有关,而测量大小就是值的View实际大小。

当然,这只是我们的初步猜测。

要搞清楚具体信息,就要从View树的绘制测量开始说起。

DecorView的测量

上文说到,测量代码是从ViewRootImpl的measureHierarchy开始的,然后会执行到performMeasure方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 private void measureHierarchy(){
  childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
        childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
 }


    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

很明显,在这里就会进行第一次MeasureSpec的计算,并且传给了下层的mView,也就是DecorView。

那我们就来看看DecorView的MeasureSpec测量规格计算方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

所以DecorView是和它的LayoutParams有关,其实也就是跟Window的调整有关,如果Window是子窗口,那么就可以调整,比如Dialog的宽高设置为WRAP_CONTENT,那么DecorView对应的测量规格就是AT_MOST

到此,我们也可以初步得到这个测量规格mode的含义:

  • 如果View的值是确定大小,比如MATCH_PARENT或者固定值,那么它的测量模式就是MeasureSpec.EXACTLY
  • 如果View的值是自适应,比如WRAP_CONTENT,那么它的测量模式就是 MeasureSpec.AT_MOST

具体是不是这样呢?我们继续到下层View一探究竟。

View/ViewGroup的测量

对于具体的View/ViewGroup 测量,就涉及到另外的一个方法measureChildWithMargins,这个方法也是在很多布局中会看到,比如LinearLayout。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

代码不多,首先获取子View的LayoutParams。然后根据 padding、margin、width 以及 parentWidthMeasureSpec 算出宽的测量模式——childWidthMeasureSpec

高度测量模式同理。

到此,我们的认识又前进了一步,对于子View的测量模式MeasureSpec肯定是和两个元素有关:

  • 子View的LayoutParams(包括margin,width)
  • 父View的MeasureSpec (再加上padding)

继续看看getChildMeasureSpec方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

代码其实很简单,就是对子View的LayoutParams和父View的specMode、specSize,共同计算出子View的MeasureSpec

举其中一个例子,当父view的测量模式为MeasureSpec.EXACTLY,子View宽的LayoutParams为MATCH_PARENT。想象一下,这种情况,子View的宽肯定就会占满父View的大小,所以子View的测量模式中的mode肯定就是确定值,为MeasureSpec.EXACTLY,而大小就是父View的大小了。对应的代码就是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
case MeasureSpec.AT_MOST:
if (childDimension == LayoutParams.MATCH_PARENT) {
    // Child wants to be our size. So be it.
    resultSize = size;
    resultMode = MeasureSpec.EXACTLY;
} 

综合所有的情况,很经典的一张表格就来了:

这里我们也可以明确了MeasureSpec中mode的含义:

  • MeasureSpec.EXACTLY。父View可以确定子View的精确大小,比如子View大小是固定的值,在所有的情况下都会是EXACTLY模式。
  • MeasureSpec.AT_MOST。父View给定一个最大的值,意思是子View大小可以不确定,但是肯定不能超过某个最大的值,例如窗口的大小。
  • MeasureSpec.UNSPECIFIED。父View对子View完全没限制,要多大给多大。这个模式似乎听起来有点奇怪?待会我们再细谈。

到此,似乎就结束了?当然没啦,获取子View的MeasureSpec之后,子View又会怎么处理呢?

View对于MeasureSpec的处理

继续上文,测量子View的测量规格之后,会调用child.measure方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void measureChildWithMargins() {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
 onMeasure(widthMeasureSpec, heightMeasureSpec);
}
    

child.measure方法也就是View的measure方法,也就是走到了onMeasure方法,继续看看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        if (optical != isLayoutModeOptical(mParent)) {
            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

哦~最后原来是给子View的measuredWidthmeasuredHeight赋值了,所赋的值就是getDefaultSize方法返回的大小。

而这个measuredWidth是干嘛的呢?搜索一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final int getMeasuredWidth() {
 //MEASURED_SIZE_MASK用于限制大小的
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

这不就是我们获取view的大小调用的方法吗?所以小结一下:

  • 父view通过父View的MeasureSpec和子View的LayoutParams算出了子View的MeasureSpec
  • 然后子View通过MeasureSpec计算了measuredWidth
  • 而这个measuredWidth也就是我们可以获取View宽高所调用的方法。

最后就是看看getDefaultSize方法干了啥,也就是验证MeasureSpec中size是不是就是我们要获取的View的宽高呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)

    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

可以看到,在AT_MOSTEXACTLY这两种常用的情况下,确实是等于测量大小specSize的。

只是在一个特殊情况,也就是UNSPECIFIED的时候,这个大小会等于getSuggestedMinimumWidth()方法的大小。

问题来了,UNSPECIFIED模式到底是啥,getSuggestedMinimumWidth()方法又做了什么?

UNSPECIFIED

很多文章会忽略这个模式,其实它也是很重要的,在前两天的讨论群中,我们还讨论了这个问题,一起看看吧~

首先,我们看看什么时候会存在UNSPECIFIED模式呢?它的概念是父View对子View的大小没有限制,很容易想到的一个控件就是ScrollView,那么在ScrollView中肯定有对这个模式的设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
                heightUsed;
        final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
                Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
                MeasureSpec.UNSPECIFIED);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

没错,在ScrollView中重写了measureChildWithMargins方法,比对下刚才ViewGroup的measureChildWithMargins方法,发现有什么不对了吗?

childWidthMeasureSpec的计算没有什么变化,还是调用了getChildMeasureSpec方法,但是childHeightMeasureSpec不对劲了,直接调用了makeSafeMeasureSpec方法生成了MeasureSpec,而且!而且!直接把SpecMode设置成了MeasureSpec.UNSPECIFIED

也就是对于子View的高度是无限制的,这也符合ScrollView的理念。

所以当ScrollView嵌套一个普通View的时候,就会触发刚才getDefaultSize中UNSPECIFIED的逻辑,也就是View的实际大小为getSuggestedMinimumWidth的大小。

继续看看getSuggestedMinimumWidth到底获取的是什么大小:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }

就一句代码:

  • 如果view的背景为null,则等于最小宽度mMinWidth。
  • 如果view的背景不为null,则等于最小宽度和 背景的最小宽度 中取较大值。

所以如果View没有设置背景,没有设置mMinWidth,那么ScrollView嵌套View的情况,View的宽度就是为0,即使设置了固定值也没用。

这只是UNSPECIFIED在普通View中的处理情况,不同的情况对UNSPECIFIED的处理方式都不一样,比如TextView、RecycleView等等。

下次会专门出一篇UNSPECIFIED的文章,到时候见。

总结

今天回顾了MeasureSpec的相关知识点:

MeasureSpec的基本概念:

  • MeasureSpec为一个32位的int值。
  • SpecMode为高两位,一共三种模式,代表父View对子View的大小限制模式,比如最大可用大小——AT_MOST。
  • SpecSize为低30位,代表父View给子View测量好的宽高。这个宽高大概率等于View的实际宽高,但是也有例外情况,也就是UNSPECIFIED的情况。

测量流程中的MeasureSpec:

  • View输的测量流程开始于ViewRootImpl的measureHierarchy,也是在这里开始了第一次MeasureSpec的计算。
  • 第一次MeasureSpec的计算也就是DecorView的MeasureSpec计算,是通过自身的LayoutParams相关,也就是和Window大小有关。
  • 然后就开始子View/ViewGroup的MeasureSpec计算,是通过父View的MeasureSpec和子View的LayoutParams相关。
  • 计算完子View的MeasureSpec之后,就开始调用onMeasure方法,计算出View的实际大小。
  • 如果是UNSPECIFIED模式,实际大小为。否则实际大小就等于计算好的specSize

参考

Android开发艺术探索》

感谢大家的阅读,有一起学习的小伙伴可以关注下公众号—码上积木❤️ 每日一个知识点,建立完整体系架构。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上积木 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go语言字符串基础
1.字符串是由一串Unicode字符组成的序列,每个Unicode字符都占用一个或多个字节的存储空间。
周小末天天开心
2023/10/16
2420
Golang 分割字符串
在开发过程中,很多时候我们有分割字符串的需求,即把一个字符串按照某种分割符进行切割。
恋喵大鲤鱼
2023/03/08
3.1K0
Go 字符串操作
要修改字符串,可先将其转换成 []rune 或 []byte,完成后再转换为 string。无论哪种转换,都会重新分配内存,并复制字节数组。
看、未来
2022/06/19
4320
Go 字符串操作
Go语言中的字符串
Go语言中的字符串也可以使用比较操作符 <, <=, ==, !=, >, >=。具体比较方法是将字符串转化成的字节数组中的字节逐一比较。
宅蓝三木
2024/10/09
1550
【转】Go语言---strings包(字符串操作)
字符串求长度 求子串 是否存在某个字符或者子串 子串出现的次数(字符串匹配) 字符串分割(切分)成[]string 字符串是否存在某个前缀或后缀 字符或者子串在字符串中首次出现的位置或最后一次出现的位置 通过某个字符串将[]string进行拼接 字符串重复次数 字符串中子串替换 大小写转换 ......................等等一些基本操作。 由于string类型可以看成是一种特殊的slice类型,因此获取长度可以用内置的函数len;同时支持 切片 操作,因此,子串获取很容易。
yiduwangkai
2019/09/17
1K0
Go语言编程中字符串切割方法小结
1.func Fields(s string) []string,这个函数的作用是按照1:n个空格来分割字符串最后返回的是 []string的切片 import ( "fmt" "strings" ) func main() { fmt.Println(strings.Fields("hello widuu golang")) //out [hello widuu golang] } 2.func FieldsFunc(s string, f func(rune) bool) []string一看
李海彬
2018/03/20
2.5K0
区块链开发之Go语言—字符串和字节
字符串与字节的关系 Go 代码使用 UTF-8 编码,字符串和字节之间的转换依据的是UTF-8编码。注意中文是3个字节对应一个中文的字符串。 下面将归类讲述负责操作字符串和字节的几个标准库 strings 包提供了很多操作字符串的简单函数,通常一般的字符串操作需求都可以在这个包中找到。 bytes 包提供了对应操作字节的函数。 strconv 包提供了基本数据类型和字符串之间的转换。这个包之所以存在,是因为在Go中,没有隐式类型转换。字符串类型和 int、float、bool 等类型之间的转换却没有这么简单
linxinzhe
2018/04/10
1.4K0
Go 字符串处理
因为字符串类型在Go中是不可改变的,因此每次操作实际都要新分配字符串,所以在字符串比较多的时候效率不高。
孤烟
2020/09/27
8110
Golang语言社区--标准库strings包讲解
大家好,我是Golang语言社区主编彬哥,本篇文章是给大家转载关于标准库strings包的知识。
李海彬
2018/03/13
2.3K0
Golang语言社区--标准库strings包讲解
Go字符串
字符串 字符集用来做什么 字符集是为每个字符分配一个唯一的ID 在同一个字符集内,字符的ID是唯一的,不同字符集ID可能是不同的 UTF-8是编码规则或者说是Unicode的一种实现 UTF-8将Unicode中的字符ID以某种方式进行编码 变长的编码规则: 1-4字节,具体规则: 0xxxx表示0~127代表ascii Go语言中的字符串内部实现编码是UTF-8的,默认是rune类型 字符串是什么? 定义字符串 双引号和反引号 golang中单引号,双引号代表的含义 var ch = 'a' 代表ut
Wyc
2023/02/27
3340
转--Go语言常用字符串处理方法实例汇总
package main import ( "fmt" "strings" //"unicode/utf8" ) func main() { fmt.Println("查找子串是否在指定的字符串中") fmt.Println(" Contains 函数的用法") fmt.Println(strings.Contains("seafood", "foo")) //true fmt.Println(strings.Contains("seafood", "
李海彬
2018/03/20
7830
【Go 基础篇】Go 语言字符串函数详解:处理字符串进阶
大家好!继续我们关于Go语言中字符串函数的探索。字符串是编程中常用的数据类型,而Go语言为我们提供了一系列实用的字符串函数,方便我们进行各种操作,如查找、截取、替换等。在上一篇博客的基础上,我们将继续介绍更多字符串函数的用法和示例。(*^_^*)💕💕💕💕
繁依Fanyi
2023/10/12
7690
【Go 基础篇】Go 语言字符串函数详解:处理字符串进阶
golang之旅--数据类型之字符串
背景 学习go已经有很长一段时间了,对于它的数据类型还没有更加深入的了解,这里做一下对数据类型的总结,第一篇是字符串的介绍。 golang中的字符串 func stringDemo() { str := "李阳" //len函数返回的是字节长度 fmt.Println(len(str)) //utf8的RuneCountInString判断的是ASCII长度 fmt.Println(utf8.RuneCountInString(str)) } 字符串
李海彬
2018/03/27
1.4K0
Go基础——字符串
字符串结构由两个信息组成:第一个是字符串指向的底层字节数组,第二个是字符串的字节的长度。字符串其实是一个结构体,因此字符串的赋值操作也就是reflect.StringHeader结构体的复制过程,并不会涉及底层字节数组的复制。在前面数组一节提到的[2]string字符串数组对应的底层结构和[2]reflect.StringHeader对应的底层结构是一样的,可以将字符串数组看作一个结构体数组。 我们可以看看字符串“Hello, world”本身对应的内存结构:
羊羽shine
2019/05/28
5660
【Go】标准库strings包
package main import ( "fmt" "strings" ) func main() { str1 := "helloRegan" str2 := "Regan" fmt.Println(strings.Contains(str1,str2)) fmt.Println(strings.ContainsAny(str1,str2)) fmt.Println(strings.ContainsRune(str1,'R')) fmt.Println(strings.Conta
Regan Yue
2021/09/16
3050
GO-字符串常用操作
package main import ( "fmt" "strconv" "strings" ) func main() { /*字符串基本操作--strings*/ str := "wangdy" //是否包含 fmt.Println(strings.Contains(str, "wang"), strings.Contains(str, "123")) //true false //获取字符串长度
李海彬
2018/03/27
6490
Go 语言字符串使用方式与技巧
关于 Go 语言字符串的使用,我们需要了解标准库 strconv 和标准库 strings 的使用方式,它们分别用于字符串类型转换和字符串操作。
frank.
2023/12/14
2700
Go 语言字符串使用方式与技巧
Golang语言之字符串操作
转义字符 verb 含义 %d 十进制整数 %x,%X 大小写方式显式十六进制整数 %o 八进制整数 %b 二进制整数 %f,%g,%e 浮点数 %t 布尔值 %c 字符 %s 字符串 %q 带双引号的字符串 %v 内置格式内容 %T 类型 %p 内存地址 %% 字符% \n 换行 \t 缩进 ---- 文章内容主要以代码注释讲解相关知识点,代码阅读时请注意注释内容。 字符串与数值相互转换 package main import ( "fmt" "strconv" ) func ma
frank.
2020/07/23
8620
第七章 字符串
字符串可以使用 双引号(" ")或者 反引号(` `)来创建。双引号用来创建可解析的字符串,但不能用来引用多行,这也是大多数字符串的定义方式。
宇宙之一粟
2020/10/26
2990
第七章 字符串
golang学习笔记——字符串操作
fmt.Println(strings.Contains(str, "hello"))
码缘
2021/03/04
7560
相关推荐
Go语言字符串基础
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档