初级会员
  • 第 43354 位会员
  • xuanwen
  • 2019-09-28 12:40:04
  • Offline
  • 19 87

最近发布的文章

    暂无

最近分享的资源

    暂无

最近发布的项目

    暂无

最近的评论

  • 评论了主题 go函数与方法的区别
    ### 面向过程与面向对象的区别 一时想不到怎么更好的用通俗的语言解释这种两种的区别,请允许我借用其他人的解释 `https://www.cnblogs.com/strivers/p/6681876.html` **面向过程**(你说的函数)就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 **面向对象**(你说的方法)是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。 ### 补充一:结构体名字没有首字母大写 不确定你是不是还在新手村,还是只是单独的举个简单例子,注意到你的结构体名字没有首字母大写,我就多啰嗦一句。 Go语言中字母大写 代替了 public,小写为private `没有首字母大写别的包无法调用,函数体与方法都是` ### 补充二: 程序里面方法和函数有区别吗? 那东西不是同一个含义吗? 我记得在我的概念里面是一个是全局函数/常规函数/通用函数---你说的函数,另外一个是某某类的函数,某某对象的函数---你说的方法 我不确定是不是自己的概念出问题啦,需要其他人确认一下。 我接触到的几种编程语言基本上定义函数/方法都是 function这个单词,要不就没有 为此我专门去查了几种比较常见的编程语言定义函数/方法的格式 #### C定义函数关键词:无 ```c 返回值类型 方法名称(参数类型 参数名称,……) { 方法内容 } ``` #### C++定义函数关键词:无 ```c++ 返回值类型 函数名(参数类型 参数名称,…… ) { 方法内容 } ``` #### Java定义函数关键词:无 ```java 修饰符(public static)返回值类型 方法名称(参数类型 参数名称,……){ 方法体 return 返回值; } ``` #### php定义函数关键词:function ``` function 方法名称(参数名称,……) { // 要执行的代码 } ``` python3定义函数关键词:def ``` python def 函数名(参数名称,……): 函数体 ``` #### js定义函数关键词:function ```javascript function 方法名称(参数名称,……) { // 执行代码 } ``` #### Go定义函数关键词:func ```golang func 函数名(参数名称 参数类型,……) [返回值名称 返回值类型,……] { 函数体 } ``` #### 总结:在这些语言里面定义函数/方法的关键词为 C、C++、JAVA的关键词: **无** PHP、JS、Go的关键词: **function及其简写** Python3的关键词: **define的简写def** 我有很大的把握确定,`函数与方法很可能是编程语言里面同一个概念的不同中文翻译` ### 数据收集 不过以上都是我一家之言,并没有100%把握;所以后面的人如果方便的话,做个统计。 在你们的理念里面,函数与方法是两个不同的东西吗? **相同**的请回复 `1`; **不相同**的请回复 `2`;
  • #### 为什么涉及结构体,简短变量声明的规则会报错 根据《Go语言圣经》里面的 2.3.1. 简短变量声明一节提到 http://books.studygolang.com/gopl-zh/ch2/ch2-03.html ``` 这里有一个比较微妙的地方:简短变量声明左边的变量可能并不是全部都是刚刚声明的。如果有一些已经在相同的词法域声明过了(§2.7),那么简短变量声明语句对这些已经声明过的变量就只有赋值行为了。 ``` 按照这个理论的话,就出现了楼主的疑问 不过楼主的代码不完整,我补充了一个更简单完整点的 ```golang package main import "fmt" type Page struct { Title string Body string } func main() { // 正确的 --- 在这里a是赋值行为,b是声明行为 var a string = "111" a, b := GetString() fmt.Printf("a:%s; b:%s\n", a, b) // 输出 a:aaa; b:bbb // 错误的---??? 为什么同样是简短变量声明,这里会出现问题 // 按照简短变量声明的理论来说,p.Body应该是赋值行为,d是声明行为 /*p := Page{} p.Body, d := GetString() fmt.Printf("p.Body:%s; d:%s\n", p.Body, d)*/ } func GetString() (a string, b string) { return "aaa", "bbb" } ``` 以上是我看了楼主的问题,个人猜测楼主的疑问是这样来的?不过我也不太清楚原理,只能等待他人补充
  • 评论了主题 小白求助
    #### 这里有个slice扩容的基础知识 **规则1: 如果切片的容量`小于1024`个元素,那么扩容的时候slice的cap就直接`翻番,乘以2`;一旦元素个数`超过1024`个元素,cap扩容就要减缓,变成了`四分之一,乘以0.25`,即每次增加原来容量的四分之一。** **规则2: 如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。** ```golang package main import ( "fmt" ) func main() { x := []int{} lastCapX := 0 for i := 0; i < 1026; i++ { x = append(x, i) fmt.Printf("len=%d cap=%d 扩容:%d \n", len(x), cap(x), cap(x)-lastCapX) lastCapX = cap(x) } } /** len=1 cap=1 扩容:1 len=2 cap=2 扩容:1 len=3 cap=4 扩容:2 len=4 cap=4 扩容:0 len=5 cap=8 扩容:4 len=6 cap=8 扩容:0 len=7 cap=8 扩容:0 len=8 cap=8 扩容:0 len=9 cap=16 扩容:8 len=10 cap=16 扩容:0 len=11 cap=16 扩容:0 . . len=16 cap=16 扩容:0 len=17 cap=32 扩容:16 len=18 cap=32 扩容:0 len=19 cap=32 扩容:0 . . len=31 cap=32 扩容:0 len=32 cap=32 扩容:0 len=33 cap=64 扩容:32 len=34 cap=64 扩容:0 . . len=127 cap=128 扩容:0 len=128 cap=128 扩容:0 len=129 cap=256 扩容:128 len=130 cap=256 扩容:0 . . len=255 cap=256 扩容:0 len=256 cap=256 扩容:0 len=257 cap=512 扩容:256 len=258 cap=512 扩容:0 len=259 cap=512 扩容:0 . . len=511 cap=512 扩容:0 len=512 cap=512 扩容:0 len=513 cap=1024 扩容:512 len=514 cap=1024 扩容:0 len=515 cap=1024 扩容:0 . . len=1023 cap=1024 扩容:0 len=1024 cap=1024 扩容:0 len=1025 cap=1280 扩容:256 len=1026 cap=1280 扩容:0 */ ``` ##### 上面的例子验证了规则1 ##### 1楼的例子验证了规则2 相信这些应该能够解开你的疑惑
  • `再次感谢@avtion的解惑` 个人平常关注底层理论还是太少、太浅 (厚脸皮不承认自己水平不够) 鉴于楼上的解答,知道了golang的slice的魔幻操作 所以我对这个问题进行了一下拓展,思考除slice外的map,struct,[]struct,[]map的修改,会有什么不同? #### 先上结论: ```golang array ---------- 传值 ---- 新的 赋值即可 slice ---------- 传址(append 后切断联系) ---- 新的 使用copy函数 map ---------- 传址 ---- 新的 for循环深度复制 struct ---------- 传值 ---- 新的 赋值即可 []struct ---------- 传址 ---- 新的 使用copy函数 []map ---------- 传址 ---- 新的 使用copy函数后还需要对map做for循环深度复制 ``` 鉴于我的测试代码实在太多,发布在这里排版可能不太好看,所以需要去github看 **github地址**: https://github.com/GrayMi/goNote/tree/master/0001-go%E8%AF%AD%E8%A8%80%E5%A4%8D%E6%9D%82%E7%B1%BB%E5%9E%8B%E7%9A%84%E4%BC%A0%E5%80%BC%E4%B8%8E%E4%BC%A0%E5%9D%80 如有发现错误或有歧义的地方,请帮忙指出,谢谢!
  • 根据楼上3楼的说法,我写了个例子进行测试 ```golang package main import ( "fmt" ) // 先改变slice元素,再增加长度 ---- 原slice元素改变,新slice改变 func Modify3(array []int) []int { array[0] = 300 t1 := append(array, 6) return t1 } // 先改变slice元素,再缩小长度 ---- 原slice元素改变,新slice改变 func Modify4(array []int) []int { array[0] = 300 t1 := array[0:3] return t1 } // 先增加长度,再改变新slice元素值 ---- 原slice元素不改变,新slice改变 func Modify5(array []int) []int { t1 := append(array, 6) t1[0] = 300 return t1 } // 先增加长度,再改变原slice元素值 ---- 原slice元素改变,新slice不改变 func Modify6(array []int) []int { t1 := append(array, 6) array[0] = 300 return t1 } // 先缩小长度,再改变原slice元素值 ---- 原slice元素改变,新slice改变 func Modify7(array []int) []int { t1 := array[0:3] array[0] = 300 return t1 } // 先缩小长度,再改变新slice元素值 ---- 原slice元素改变,新slice改变 func Modify8(array []int) []int { t1 := array[0:3] t1[0] = 300 return t1 } func main() { arr1 := []int{1, 2, 3, 4, 5} arr2 := Modify3(arr1) fmt.Println("arr1:", arr1) // 打印结果:[300 2 3 4 5] fmt.Println("arr2:", arr2) // 打印结果:[300 2 3 4 5 6] arr3 := []int{1, 2, 3, 4, 5} arr4 := Modify4(arr3) fmt.Println("arr3:", arr3) // 打印结果: [300 2 3 4 5] fmt.Println("arr4:", arr4) // 打印结果: [300 2 3] arr5 := []int{1, 2, 3, 4, 5} arr6 := Modify5(arr5) fmt.Println("arr5:", arr5) // 打印结果: [1 2 3 4 5] fmt.Println("arr6:", arr6) // 打印结果: [300 2 3 4 5 6] arr7 := []int{1, 2, 3, 4, 5} arr8 := Modify6(arr7) fmt.Println("arr7:", arr7) // 打印结果: [300 2 3 4 5] fmt.Println("arr8:", arr8) // 打印结果: [1 2 3 4 5 6] arr9 := []int{1, 2, 3, 4, 5} arr10 := Modify7(arr9) fmt.Println("arr9:", arr9) // 打印结果: [300 2 3 4 5] fmt.Println("arr10:", arr10) // 打印结果: [300 2 3] arr11 := []int{1, 2, 3, 4, 5} arr12 := Modify8(arr11) fmt.Println("arr11:", arr11) // 打印结果: [300 2 3 4 5] fmt.Println("arr12:", arr12) // 打印结果: [300 2 3] } ``` ```golang 输出结果: $ go run main.go arr1: [300 2 3 4 5] arr2: [300 2 3 4 5 6] arr3: [300 2 3 4 5] arr4: [300 2 3] arr5: [1 2 3 4 5] arr6: [300 2 3 4 5 6] arr7: [300 2 3 4 5] arr8: [1 2 3 4 5 6] arr9: [300 2 3 4 5] arr10: [300 2 3] arr11: [300 2 3 4 5] arr12: [300 2 3] $ go version go version go1.13 linux/amd64 ``` #### 实验总结 ```golang |----------------------------------------------------------------------------| | | | Modify3 先改变slice元素,再增加长度 ---- 原slice元素改变,新slice改变 | | Modify4 先改变slice元素,再缩小长度 ---- 原slice元素改变,新slice改变 | | | | Modify5 先增加长度,再改变新slice元素值 ---- 原slice元素不改变,新slice改变 | | Modify6 先增加长度,再改变原slice元素值 ---- 原slice元素改变,新slice不改变 | | | | Modify7 先缩小长度,再改变原slice元素值 ---- 原slice元素改变,新slice改变 | | Modify8 先缩小长度,再改变新slice元素值 ---- 原slice元素改变,新slice改变 | | | |---------------------------------------------------------------------------| 原slice append 扩容后,原始slice与新slice脱离关系 原slice 缩小后,原始slice与新slice保持关系 ``` #### 实验结论 当函数内部发生slice扩容后,会导致底层数组改变,就不会影响外部作用域的底层数组,经以上代码证明是正确的 但是当函数内部发生slice发生减少的时候,则不会导致底层数组改变,会影响外部作用域的底层数组 感谢楼上指出我的错误 #### 剩余疑问 ```golang 我全文搜索go源码文件,没有发现3楼的slice结构定义,发现没有找到 // 3楼的slice结构定义 type _slice struct { elements unsafe.Pointer // 引用着底层存储在间接部分上的元素 len int // 长度 cap int // 容量 } // 我的slice结构定义--位于源码位置/**/go/src/go/types/type.go type Slice struct { Elem *Type // element type } ``` 我不确定我是否找对地方,还是我们两者的go版本不一致 我的go版本为go version go1.13 linux/amd64 希望对楼主有点帮助