如何python 构建树结构不可变的类结构

什么是不可变数据结构? - 知乎2被浏览118分享邀请回答0添加评论分享收藏感谢收起I'm currently programming in Scala, but I guess this applies to any functional programming language, or rather, any programming language that recommends immutability and can interact with a database.
When I fetch data from my database, I map it to a model data structure. In functional programming, data structures tend to be immutable. But the data in a database is mutable, so I wonder whether or not my model should be mutable as well. In general, what would be a good and well-accepted practice in such a case?
Following Scala courses by Martin Odersky on Coursera, I remember he said something like:
It's better to use immutable data structures, but when you want to
interact with the real world, it can be useful to use mutable data
structures.
So, again, I wonder what should I do. As of now, my data structures are immutable, and this is leading to a lot of boilerplate code when I want to update a record in my database. Would using a mutable model help reduce this boiler plate?
(I already asked , but I wasn't satisfied with the actual answers, so I've generalized it here.)
解决方案 "Interacting with the real world" has nothing to do with whether you use mutable or immutable data structures. This is a furfy that is repeated all too often and it is great that you have questioned it.
While it is typically more healthy to dismiss garbage like this, you might be interested in a cursory debunking:
However, I strongly recommend dismissing it and moving on.
Onto your question, you say you have boilerplate when you want to perform operations on your immutable data structures. In fact, there is very well established theory that solves this problem to a large extent. Here is a paper written about it using Scala:
Hope that helps.
本文地址: &
我目前在Scala中编程,但我想这适用于任何函数式编程语言,或者更确切地说,任何推荐不可变性并且可以与数据库交互的编程语言。
当我从我的数据库获取数据时,我将其映射到模型数据结构。在函数式编程中,数据结构往往是不可变的。但是数据库中的数据是可变的,所以我不知道我的模型是否应该是可变的。
在Coursera的Martin Odersky的Scala课程之后,我记得他说的是这样的: / p>
最好使用不可变的数据结构,但是当你想要与真实世界交互时,对于使用可变数据结构非常有用。
因此,我不知道该怎么办。到目前为止,我的数据结构是不可变的,这导致了很多样板代码,当我想更新我的数据库中的记录。使用可变模型有助于减少此锅炉板吗?
(我已经问过
但是,我强烈建议您关闭它并继续操作。在您的问题上,当您想对不可变的数据结构执行操作时,您说您有样板。事实上,有非常成熟的理论在很大程度上解决了这个问题。这是一篇使用Scala写的文章:
希望有所帮助。
本文地址: &
扫一扫关注官方微信什么是不可变对象?
众所周知, 在中, String类是不可变的。那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。
区分对象和对象的引用
对于Java初学者, 对于String是不可变对象总是存有疑惑。看下面代码:
String s = "ABCabc";
System.out.println("s = " + s);
s = "123456";
System.out.println("s = " + s);
&打印结果为: s = ABCabc
s = 123456首先创建一个String对象s,然后让s的值为“ABCabc”, 然后又让s的值为“123456”。 从打印结果可以看出,s的值确实改变了。那么怎么还说String对象是不可变的呢? 其实这里存在一个误区: s只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象。 也就是说,s只是一个引用,它指向了一个具体的对象,当s=“123456”; 这句代码执行过之后,又创建了一个新的对象“123456”, 而引用s重新指向了这个心的对象,原来的对象“ABCabc”还在内存中存在,并没有改变。内存结构如下图所示:
Java和C++的一个不同点是, 在Java中不可能直接操作对象本身,所有的对象都由一个引用指向,必须通过这个引用才能访问对象本身,包括获取成员变量的值,改变对象的成员变量,调用对象的方法等。而在C++中存在引用,对象和指针三个东西,这三个东西都可以访问对象。其实,Java中的引用和C++中的指针在概念上是相似的,他们都是存放的对象在内存中的地址值,只是在Java中,引用丧失了部分灵活性,比如Java中的引用不能像C++中的指针那样进行加减运算。&
为什么String对象是不可变的?
要理解String的不可变性,首先看一下String类中都有哪些成员变量。 在JDK1.6中,String的成员变量有以下几个:
public final class String
implements java.io.Serializable, Comparable&string&, CharSequence{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int
/** The count is the number of characters in the String. */
private final int
/** Cache the hash code for the string */
private int // Default to 0&/string&
在JDK1.7中,String类做了一些改动,主要是改变了substring方法执行时的行为,这和本文的主题不相关。JDK1.7中String类的主要成员变量就剩下了两个:
public final class String
implements java.io.Serializable, Comparable&string&, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int // Default to 0&/string&
由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装。JDK6中, value是String封装的数组,offset是String在这个value数组中的起始位置,count是String所占的字符的个数。在JDK7中,只有一个value变量,也就是value中的所有字符都是属于String这个对象的。这个改变不影响本文的讨论。 除此之外还有一个hash成员变量,是该String对象的哈希值的缓存,这个成员变量也和本文的讨论无关。在Java中,数组也是对象(可以参考我之前的文章java中数组的特性)。 所以value也只是一个引用,它指向一个真正的数组对象。其实执行了String s = “ABCabc”; 这句代码之后,真正的内存布局应该是这样的:&
value,offset和count这三个变量都是private的,并且没有提供setValue, setOffset和setCount等公共方法来修改这些值,所以在String类的外部无法修改String。也就是说一旦初始化就不能修改, 并且在String类的外部不能访问这三个成员。此外,value,offset和count这三个变量都是final的, 也就是说在String类内部,一旦这三个值初始化了, 也不能被改变。所以可以认为String对象是不可变的了。&那么在String中,明明存在一些方法,调用他们可以得到改变后的值。这些方法包括substring, replace, replaceAll, toLowerCase等。例如如下代码:
String a = "ABCabc";
System.out.println("a = " + a);
a = a.replace('A', 'a');
System.out.println("a = " + a);
&打印结果为: a = ABCabc
a = aBCabc那么a的值看似改变了,其实也是同样的误区。再次说明, a只是一个引用, 不是真正的字符串对象,在调用a.replace('A', 'a')时, 方法内部创建了一个新的String对象,并把这个心的
对象重新赋给了引用a。String中replace方法的可以说明问题
读者可以自己查看其他方法,都是在方法内部重新创建新的String对象,并且返回这个新的对象,原来的对象是不会被改变的。这也是为什么像replace, substring,toLowerCase等方法都存在返回值的原因。也是为什么像下面这样调用不会改变对象的值:&
String ss = "123456";
System.out.println("ss = " + ss);
ss.replace('1', '0');
System.out.println("ss = " + ss);
&打印结果: ss = 123456
ss = 123456
String对象真的不可变吗?
从上文可知String的成员变量是private final 的,也就是初始化之后不可改变。那么在这几个成员中, value比较特殊,因为他是一个引用变量,而不是真正的对象。value是final修饰的,也就是说final不能再指向其他数组对象,那么我能改变value指向的数组吗? 比如将数组中的某个位置上的字符变为下划线“_”。 至少在我们自己写的普通代码中不能够做到,因为我们根本不能够访问到这个value引用,更不能通过这个引用去修改数组。 那么用什么方式可以访问私有成员呢? 没错,用反射, 可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。下面是实例代码:&
public static void testReflection() throws Exception {
//创建字符串"Hello World", 并赋给引用s
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueFieldOfString.setAccessible(true);
//获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s);
//Hello_World
打印结果为: s = Hello World
s = Hello_World在这个过程中,s始终引用的同一个String对象,但是再反射前后,这个String对象发生了变化, 也就是说,通过反射是可以修改所谓的“不可变”对象的。但是一般我们不这么做。这个反射的实例还可以说明一个问题:如果一个对象,他组合的其他对象的状态是可以改变的,那么这个对象很可能不是不可变对象。例如一个Car对象,它组合了一个Wheel对象,虽然这个Wheel对象声明成了private final 的,但是这个Wheel对象内部的状态可以改变, 那么就不能很好的保证Car对象不可变。
阅读(...) 评论()3大数据结构类之——不可变数组NSArray - 简书
3大数据结构类之——不可变数组NSArray
OC的数组同样分为不可变数组和可变数组,可变数组是不可变数组的子类,先来说不可变速数组
//1.创建数组对象
//创建空的数组对象
NSArray * array=@[];//字面量方法
NSArray * array1=[[NSArray alloc]init];//对应的构造方法
NSArray * array2=[NSArray array];//对应的类方法
//创建非空数组
//1.1字面量创建,不同于C语言的数组,OC的数组只能存对象
NSArray * arr = @[@1,@2,@3,@4];
NSLog(@"arr(%p) = %@",arr,arr);
//1.2通过构造方法创建数组
NSArray * arr1 = [[NSArray alloc]initWithObjects:@"1",@"2",@"3", nil];
NSLog(@"arr1(%p) = %@",arr1,arr1);
//1.3对应的类方法
NSArray * arr2 = [NSArray arrayWithObjects:@"1",@"2",@"3", nil];
NSLog(@"arr2(%p) = %@",arr2,arr2);
//1.4根据已有的数组构造数组
NSArray * arr3 = [[NSArray alloc]initWithArray:arr];
NSLog(@"arr3(%p) = %@",arr3,arr3);
//1.5对应的类方法
NSArray * arr4 = [NSArray arrayWithArray:arr];
NSLog(@"arr4(%p) = %@",arr4,arr4);
创建数组.png
数组查询的相关方法
NSArray * arr = @[@1,@2,@3,@4,@1];
//根据数组元素查看第一个下标(索引)
NSInteger index = [arr indexOfObject:@1];
NSLog(@"index = %lu",index);//index = 0
//在指定范围内查找
index = [arr indexOfObject:@1 inRange:NSMakeRange(2, 3)];
if (index == NSNotFound) {
NSLog(@"没有这个元素");
NSLog(@"index = %lu",index);//index = 4
//获取数组元素个数count arr.count是点语法,可以通过对象点出属性,其实是调用了了count方法 [arr count];
NSLog(@"arr中共有%ld个元素",arr.count);//arr中共有5个元素
//同C语言一样,可以直接根据数组下标获取数组元素
NSLog(@"arr[3] = %@",arr[3]);//arr[3] = 4
//数组越界问题
NSLog(@"arr[5] = %@",arr[5]);//数组中总共只有5个元素,其最大的下标为4
//查看输出框中,reason: '*** -[__NSArrayI objectAtIndex:]: index 5 beyond bounds [0 .. 4]',说的就是数组的下标范围是[0 .. 4],5超出范围,即越界了
//抽取指定范围的数组元素重新组成一个数组objectsAtIndexes:&#(nonnull NSIndexSet *)#&,参数是一个集合
//创建一个数字集合对象,集合中为{2,3,4}
NSIndexSet *set=[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)];
NSArray * array = [arr objectsAtIndexes:set];
NSLog(@"array = %@",array);// array = (3,4,1)
数组越界.png
数组查询.png
数组枚举相关方法
NSArray * arr = @[@1,@2,@3,@4,@1];
//枚举器,枚举器是用来读数据的
//创建一个正序枚举器
NSEnumerator * enumerator =[arr objectEnumerator];
NSLog(@"正序枚举");
while (obj = [enumerator nextObject]) {
NSLog(@"%@",obj);
15:28:56.460 OC数组[972:58313] 1
15:28:56.461 OC数组[972:58313] 2
15:28:56.462 OC数组[972:58313] 3
15:28:56.462 OC数组[972:58313] 4
15:28:56.462 OC数组[972:58313] 1
NSLog(@"快速枚举");
//快速枚举(正序),for in循环,id = void *,可以指向任意类型的指针
for (id obj in arr) {
NSLog(@"%@",obj);
15:25:24.444 OC数组[962:56523] 1
15:25:24.445 OC数组[962:56523] 2
15:25:24.445 OC数组[962:56523] 3
15:25:24.445 OC数组[962:56523] 4
15:25:24.445 OC数组[962:56523] 1
NSLog(@"逆序枚举");
//逆序枚举器
NSEnumerator * enumerator1= [arr reverseObjectEnumerator];
while (obj = [enumerator1 nextObject])
NSLog(@"%@",obj);
15:32:33.511 OC数组[986:59874] 1
15:32:33.511 OC数组[986:59874] 4
15:32:33.511 OC数组[986:59874] 3
15:32:33.511 OC数组[986:59874] 2
15:32:33.511 OC数组[986:59874] 1*/
数组字符串转换
//字符串分割到数组
NSString * string = @"Yes ,I'm a good man! What's you?";
NSArray * arr1 =[string componentsSeparatedByString:@" "];//以@" "作为分隔符切割字符串,切割下来的子串添加到数组作为数组元素
NSLog(@"arr1 = %@",arr1);
//以字符集合作为分割条件
//先创建字符集合
NSCharacterSet * set = [NSCharacterSet characterSetWithCharactersInString:@" ,!"];
//componentsSeparatedByCharactersInSet,把set作为参数进行分隔
NSArray * arr2 = [string componentsSeparatedByCharactersInSet:set];
NSLog(@"arr2 = %@",arr2);
//把数组元素拼接成字符串
NSString * str = [arr1 componentsJoinedByString:@" "];
NSLog(@"str = %@",str);//str = Yes ,I'm a good man! What's you?
数组字符串转换.png
图片说明有点错误:""出现时因为字符集合作为切割条件的时候," "和","是相邻的,这个位置切割了2次,后面的也是同样的道理
喜欢的话,帮忙点一下喜欢,谢谢!
如果有错误之处或者偏差,还请斧正!
欢迎大家留言提问,技术要交流才能更快成长!
百战程序员_ Java1573题 QQ群:034603 掌握80%年薪20万掌握50%年薪10万 全程项目穿插, 从易到难,含17个项目视频和资料持续更新,请关注www.itbaizhan.com 国内最牛七星级团队马士兵、高淇等11位十年开发经验专...
前言 OC程序必须依托于Foundation框架,Foundation框架其实就是一个类库。它包含了许多iOS/OS X开发中所必须的类。其中有3个数据结构类:字符串、数组和字典。本文就字符串类做相关讨论。 oc中的字符串 , 于给ios/mac 下应 程序服务.往后的io...
Foundation框架之 NSArray(数组) NSMutableArray 是NSAarray 的子类,所以可以使用NSAarray中定义的全部方法。NSMutableArray 是可变的,所以可随意添加或删除其中的元素。随着添加或删除操作,数组中元素的位置会前后移动...
swift的基础语法 这样吧,先把swift4.0教材的先分享给大家。swift4和swift3的基本上没有多大的差别。 1.初识swift 1.1swift中的如何导入框架 在oc中导入框架或其他头文件一般都是 而使用swift的方式进行导入 1.2定义标识符 在swif...
C语言笔记 一终端命令 ls -l显示当前工作路径下的所有的文件及文件信息 d开头文件夹 -开头文件 r读 w写 x执行 - -当前用户的权限 - -其他用户的权限 & pwd查看终端程序的工作路径 &cd切换工作路径 &clear清理屏幕 &touch新建文件 &open...
叶黄了, 树枯了, 山里的一年,就这样过去了。 时间从未停下脚步。 山移了, 路变了, 祖辈的心血,落下了。 时间从未停下脚步。 个高了, 离家了, 山里的孩子,长大了。 时间从未停下脚步。 发白了, 背驼了, 我的爷爷,也老了。 时间,请你停下脚步吧! 我想追上爷爷老去的步伐。
第四节:人世别离难 时间过的很快,越是临近孟冬月(十一月),我内心越是惆怅不已,在我的记忆中,我只同爹爹一起度过了12个春秋,一觉醒来却被告知已过了15年华。在爹爹的督导下,礼部的效率倒是全所未有的快,新秋时节(七月),便送来了大征之礼。一车又一车的聘礼,整整堆满了整条大街...
感悟精选一: 真正的朋友是什么 朋友是一种相遇。 大千世界,红尘滚滚,于芸芸众生、茫茫人海中,朋友能够彼此遇到,能够走到一齐,彼此相互认识,相互了解,相互走近,实在是缘份。在人来人往,聚散分离的人生旅途中,在各自不一样的生命轨迹上,在不一样经历的心海中,能够彼此相遇、相聚、...
大家都看到一个人之所以依赖别人,乃是因为从小依赖惯了,把这样依赖拆除,此人自然成功。 生活中的道理就是这样的,对待子女教育,溺爱之,这种过分亲妮的爱只能害了他(指我儿子),正所谓穷人的孩子早当家,对待一个不爱学习的人,早点赶出家门,让社会来教育...
Yesterday night I made a decision which I decided to apply to be host.My school collaborate with educational television to set up a progr...

我要回帖

更多关于 构建高精尖经济结构 的文章

 

随机推荐