Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 124 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
124
Dung lượng
0,97 MB
Nội dung
18546228 ch14.F 1/30/03 10:51 AM Page 332 Working with Structures T his chapter discusses structures, which are the most complex and most useful of the complex data types. You learn what struc- tures are, how to use them, and when to use them. What is a Structure? Simply put, a structure is a container for other variables. Structures are like arrays in that they contain programmatically addressable ele- ments, but structures name each element rather than simply assign- ing them numeric positions. Graphically, a structure looks as shown in Figure 15-1. Figure 15-1: A graphical representation of a structure. Notice that each element in a structure has a name. Always remem- ber that each element in an array has a number, while structure ele- ments have names. You see how naming each element is useful throughout the chapter. Creating a Structure As are arrays, structures are complex objects with a specific initial- ization function, as the following example shows: <cfset myStruct = StructNew()> StructNew() doesn’t take any arguments, because structures do not have a simple dimension. As you will see in the section “Nested Structures” later in this chapter, structures may have arbitrarily com- plex dimensions. If myStruct currently contains a value, StructNew()destroys the old value and replaces it with an empty structure. 15 15 CHAPTER ✦✦✦✦ In This Chapter Understanding structures Manipulating structure keys Visualizing complex structures The various notations used in referencing structures Structure copying caveats and solutions ✦✦✦✦ 19546228 ch15.F 1/30/03 10:51 AM Page 333 334 Part III ✦ The ColdFusion MX Language Adding an Element to a Structure An element in a structure consists of a key and a value. The key is the name of the element, and the value is what the element contains. Think of the package as if each element were a variable and the structure a named container of those variables. You can add an element to a structure in multiple ways, all of which we discuss in the follow- ing sections. StructInsert() vs. StructUpdate() One way to add an element to a structure is by using StructInsert(), as follows: <cfset success = StructInsert(myStruct, “FavoriteFruit”, “apple”, “TRUE”)> The return value of StructInsert() is TRUE if the operation is successful; if unsuccessful, the function call throws an error. After the preceding call to StructInsert(), myStruct would look as follows: FavoriteFruit: apple The first argument to StructInsert() is the structure that you are inserting a key into. The second argument to StructInsert() is the name of the new key, and the third argument is the new key’s value. The fourth argument tells ColdFusion whether to permit the overwriting of an already existing key: If it is FALSE and the key already exists, ColdFusion throws an error. Note that the fourth argument defaults to FALSE if omitted. To modify an element that’s already in the structure, you can use StructUpdate(), as follows: <cfset success = StructUpdate(myStruct, “FavoriteFruit”, “pineapple”)> StructUpdate() throws an error if the specified key doesn’t already exist in the structure. After you use StructUpdate(), myStruct looks as follows: FavoriteFruit: pineapple We usually use StructInsert() by passing TRUE for the fourth parameter, because that way, you don’t need to know whether the specified key already exists before creating it. Using dot notation StructInsert and StructUpdate() are unwieldy. Take, for example, the following statement: <cfset success = StructInsert(myStruct, “SweetestFruit”, “peach”, “TRUE”)> Now compare it to the following: <cfset myStruct.SweetestFruit = “peach”> The second version is simpler and easier to read, and it does the same thing. The only draw- back to using dot notation is that you can’t embed special characters in the name of the key, as you can by using StructInsert(), as shown in the following snippet: 19546228 ch15.F 1/30/03 10:51 AM Page 334 335 Chapter 15 ✦ Working with Structures <cfset success = StructInsert(myStruct, “Biggest Fruit”, “watermelon”, “TRUE”)> <cfset myStruct.Biggest Fruit = “watermelon”> Notice that the second CFSET statement would cause a syntax error. You also can’t use dot notation to create a key name that is a number, as follows: <cfset myStruct.3182 = “some value”> This statement throws an error. You can use StructInsert() or StructUpdate() to create this key. Another problem with dot notation is that it does not preserve the case of the key. Suppose that you do the following: <cfset someStruct.SomeKey = 1> Here, someStruct contains a key named SOMEKEY, because ColdFusion converts all key names created by using dot notation to uppercase. It is unclear why this occurs, but the good news is that the uppercase keys will rarely affect your code because ColdFusion doesn’t con- sider case when looking up a key name. Using associative array notation You have yet another syntax that you can use for creating a structure key, as the following example shows: <cfset myStruct[“NotARealFruit”] = “zucchini”> That syntax is equivalent to the following: <cfset myStruct.NotARealFruit = “zucchini”> This new syntax is called associative-array notation. For an explanation, look at Figure 15-2. Figure 15-2: Side-by-side comparison of an array and a structure. Notice that the structure readout in the figure looks almost like two arrays sandwiched together — one array containing the element names and the other containing the element val- ues. These two “arrays” are associated with one another so that referring to an element in one array retrieves the element in the other array. (Note, however, that the names and values are not actually arrays; it’s just convenient to use arrays as a comparison.) The first advantage to this notation is that you can now embed special characters in the key name, as follows: <cfset myStruct[“3182”] = “some value”> <cfset myStruct[“Coolest Fruit”] = “cherry”> Another advantage is that associative-array notation preserves the case of the key name. This syntax truly is the best of both worlds — it’s as easy to use as dot notation but as flexible as StructInsert(). Given the choice between dot notation and associative-array notation, the latter is usually your best bet for creating structure keys. 19546228 ch15.F 1/30/03 10:51 AM Page 335 336 Part III ✦ The ColdFusion MX Language The real advantage to using an associative array, however, is the capability to use dynamic key names, as shown in the following example: <cfset myKeyName = “Sourest Fruit”> <cfset myStruct[myKeyName] = “lemon”> After that last call, myStruct would look as follows: FavoriteFruit: pineapple SweetestFruit: peach Biggest Fruit: watermelon NotARealFruit: zucchini Coolest Fruit: cherry Sourest Fruit: lemon Notice that, instead of storing lemon in an element named myKeyName, ColdFusion evaluates myKeyName and stores lemon in an element named Sourest Fruit. Retrieving an Element From a Structure You have two ways to retrieve an element from a structure. The simplest is to use dot nota- tion or associative-array notation, as follows: <cfoutput> #myStruct.NotARealFruit#<br> #myStruct[“Coolest Fruit”]# </cfoutput> If you’d rather use a function, use StructFind() as follows: <cfoutput> #StructFind(myStruct, “NotARealFruit”)#<br> #StructFind(myStruct, “Coolest Fruit”)# </cfoutput> Both syntaxes throw an error if the specified key does not exist. You derive no benefit from one or the other syntax, because both do the same thing, so pick whichever one you that like and use it. Using associative-array or dot notation, however, is usually much more readable. Notice that you can set an element by using associative-array notation and retrieve it by using dot notation; this is what we usually do, as the following example shows: <cfset myStruct[“TangiestFruit”] = “orange”> <cfoutput>#myStruct.TangiestFruit#</cfoutput> We set elements by using associative-array notation to preserve the case of the key, but we retrieve the element by using dot notation because it’s typically more readable. Remember, however, that you aren’t required to use only one syntax — use whichever syntax best fits the situation. Removing an Element From a Structure You delete a key from a structure by using StructDelete(), as follows: <cfset success = StructDelete(myStruct, “Coolest Fruit”)> After you call StructDelete(), myStruct looks as follows: 19546228 ch15.F 1/30/03 10:51 AM Page 336 337 Chapter 15 ✦ Working with Structures FavoriteFruit: pineapple SweetestFruit: peach Biggest Fruit: watermelon NotARealFruit: zucchini Sourest Fruit: lemon TangiestFruit: orange Coolest Fruit is gone. Notice that you never have undefined keys in a structure, which is another way that structures are different from arrays. To quickly remove all elements from a structure, use StructClear(), as follows: <cfset success = StructClear(myStruct)> After you call StructClear, myStruct still exists, but it contains no elements. Getting Information About a Structure StructIsEmpty() tells you whether any elements are in a given structure, as the following example shows: <cfif StructIsEmpty(myStruct)> To get a specific count of how many top-level (that is, nonnested) elements are in a structure, use StructCount(), as follows: <cfoutput>#StructCount(myStruct)#</cfoutput> To tell whether a given variable contains a structure, use IsStruct(), as follows: <cfif IsStruct(myStruct)> IsStruct returns TRUE if the passed variable is a structure and FALSE if it does not. Looping Over a Structure One form of CFLOOP enables you to loop over the keys in a structure, as the following exam- ple shows: <cfoutput> <cfloop collection=”#myStruct#” item=”theItem”> The value of the #theItem# key is #myStruct[theItem]#.<br> </cfloop> </cfoutput> The collection attribute tells ColdFusion which structure to loop over, and the item attribute is what ColdFusion names the variable that contains the key name. ColdFusion loops over every element in the structure and puts the key’s name in theItem each time that the loop iterates. If you don’t need to loop over the structure but you need a list or array containing the struc- ture’s keys, use StructKeyList() or StructKeyArray(), as follows: <cfset keyList = StructKeyList(myStruct)> <cfset keyArray = StructKeyArray(myStruct)> 19546228 ch15.F 1/30/03 10:51 AM Page 337 338 Part III ✦ The ColdFusion MX Language StructKeyList() takes an optional second parameter describing the delimiter to use for the list. The following line of code, for example, creates a semicolon-delimited list containing the names of the top-level keys in myStruct: <cfset keyList = StructKeyList(myStruct, “;”)> Nested Structures So far you’ve created keys containing simple string values, but the most powerful feature of structures is their capability to nest inside another structure. Nesting enables you to create hierarchical data structures that closely resemble real-world data models. The simple structure that we created earlier looks like what’s shown in Figure 15-3. Figure 15-3: A simple structure. A nested structure would look like what’s shown in Figure 15-4. Figure 15-4: Structures nested inside one another. Notice that in Figure 15-4, smaller structures are nested inside the enclosing structure. Creating a nested structure may seem complicated, but it really is quite simple. In the follow- ing example, you create a new key named FruitCosts in myStruct that contains a substruc- ture that, in turn, contains the names of fruits and their respective costs: 19546228 ch15.F 1/30/03 10:51 AM Page 338 339 Chapter 15 ✦ Working with Structures <cfset myStruct[“FruitCosts”] = StructNew()> <cfset myStruct.FruitCosts[“Oranges”] = 1.99> <cfset myStruct.FruitCosts[“Apples”] = 1.50> <cfset myStruct.FruitCosts[“Peaches”] = 1.75> Now myStruct looks like what’s shown in Figure 15-5. Figure 15-5: A substructure inside myStruct. Structures can be nested many levels deep in any configuration. You can also use associative-array notation to create nested structures, as follows: <cfset myStruct[“FruitCosts”] = StructNew()> <cfset myStruct[“FruitCosts”][“Oranges”] = 1.99> <cfset myStruct[“FruitCosts”]]”Apples”] = 1.50> <cfset myStruct[“FruitCosts”][“Peaches”] = 1.75> Our personal preference is to use dot notation for every nesting level except the final one, as in the following example: <cfset myStruct[“FruitCosts”] = StructNew()> <cfset myStruct.FruitCosts[“Oranges”] = 1.99> <cfset myStruct.FruitCosts]”Apples”] = 1.50> <cfset myStruct.FruitCosts[“Peaches”] = 1.75> Just make sure that you don’t have any special characters or spaces in your key names — or have key names made entirely of numbers — in the dot-path portion of your notation. Complex nesting After you understand the general concept of nesting structures, you can delve a little deeper into more complex nesting schemes, where one complex variable is nested within another. You can, for example, also nest arrays inside of structures, as follows: <cfset myStruct[“FruitArray”] = ArrayNew(1)> <cfset myStruct.FruitArray[1] = “orange”> <cfset myStruct.FruitArray[2] = “lemon”> <cfset myStruct.FruitArray[3] = “pineapple”> After you add the array, myStruct looks like what’s shown in Figure 15-6. 19546228 ch15.F 1/30/03 10:51 AM Page 339 340 Part III ✦ The ColdFusion MX Language Figure 15-6: An array nested inside myStruct. Structures can be nested any number of levels deep. In addition, array elements can contain structures, as the following example shows: <cfset myArray = ArrayNew(1)> <cfset myArray[1] = StructNew()> <cfset myArray[1][“MyTestKey”] = “my value”> <cfoutput> #myArray[1].MyTestKey# </cfoutput> Structures become truly useful if you use them as containers for complex data that models the real world. You can create a shopping cart by using a structure, for example, as shown in Listing 15-1. Listing 15-1: Creating a shopping cart in a structure <cfset myCart = StructNew()> <cfset myCart.cartID = CreateUUID()> <cfset myCart.saleDate = Now()> <cfset myCart.arItemNumber = ArrayNew(1)> <cfset myCart.arItemName = ArrayNew(1)> <cfset myCart.arQuantity = ArrayNew(1)> <cfset myCart.arUnitPrice = ArrayNew(1)> <cfset myCart.arExtended = ArrayNew(1)> <cfset myCart.subtotal = 0> <cfset myCart.salesTaxRate = 4.0000> <cfset myCart.salesTaxAmount = 0> <cfset myCart.shippingAmount = 0> <cfset myCart.total = 0> 19546228 ch15.F 1/30/03 10:51 AM Page 340 341 Chapter 15 ✦ Working with Structures Later on, after your shopping cart contains line items in its arrays, you can easily produce familiar values, as the following list describes: ✦ The subtotal is simply ArraySum(myCart.arExtended),. ✦ The sales-tax amount is simply ( myCart.salesTaxRate * myCart.subtotal). ✦ The total is ( myCart.subtotal + myCart.salesTaxAmount + myCart.shippingAmount). You face no limits on how much information that your structure can store, nor do you have any limits as to how complex it can be. The only thing that you must watch out for is making your structure too complicated for your needs. You can usually keep track of what goes where quite easily if you make the format of your structures emulate the real-world data that you are storing. How dot notation automatically creates a nested structure Until now, you’ve created structures only by using StructNew(). You can also create struc- tures just by using dot notation, as follows: <cfset aNewStruct.SomeKey.SomeValue = 1> That line creates a structure named aNewStruct with a substructure named SomeKey that has an element named SomeValue with a value of 1. You can visualize it as what’s shown in Figure 15-7. Figure 15-7: A structure created by using dot notation. Notice that, in the figure, the names of all newly created structures and keys are all upper- case, regardless of the capitalization that you use in the code. As convenient as this method may seem, it does have a drawback. Consider the following snippet: <cfset aNewStruct = StructNew()> <cfset aNewStruct.myKey = 2> <cfset aNewStruct.yourKey = 3> After running the preceding snippet, two new keys, named myKey and yourKey, are created, and aNewStruct looks as shown in Figure 15-8. Figure 15-8: aNewStruct. 19546228 ch15.F 1/30/03 10:51 AM Page 341 [...]... In Listing 15-2, we just use a standard collection loop, relying on whatever order ColdFusion stored the structure in In Listing 15-3, we call StructSort() first, which returns an array of key names that look as follows: 343 19 546 228 ch15.F 344 1/30/03 10:51 AM Page 344 Part III ✦ The ColdFusion MX Language 1: 2: 3: 4: 5: Apples Lemons Peaches Oranges Cherries These elements still may not seem to be... you are correct The change to myStruct.aSubStruct.subKey, however, does modify yourStruct’s value This situation is shown in Figure 15- 14 Figure 15- 14: Copying structures by using StructCopy() 347 19 546 228 ch15.F 348 1/30/03 10:51 AM Page 348 Part III ✦ The ColdFusion MX Language This result happens because of how StructCopy() copies a structure’s members As the code copied myStruct to yourStruct, it... 345 19 546 228 ch15.F 346 1/30/03 10:51 AM Page 346 Part III ✦ The ColdFusion MX Language You can sort by a key any number of levels deep by adding elements to the dot path: Be aware that, if the specified subkey doesn’t exist for every top-level element in the main structure, ColdFusion throws an error...19 546 228 ch15.F 342 1/30/03 10:51 AM Page 342 Part III ✦ The ColdFusion MX Language Suppose that you now attempt to call the following snippet to create a nested structure named myKey: If the previous line had worked, it would have overwritten the previous simple value of myKey... TheSum = 0; for(i = 1; i LTE 10; i = i + 1) { ✦ ✦ ✦ ✦ In This Chapter The differences between tag-based ColdFusion syntax and scripting syntax Setting variables by using CFSCRIPT Flow control by using scripting syntax ✦ ✦ ✦ ✦ 20 546 228 ch16.F 3 54 1/30/03 10:51 AM Page 3 54 Part III ✦ The ColdFusion MX Language TheSum = TheSum + 1; } Note CFSCRIPT doesn’t support the ++ syntax for incrementing... that calls the function We call the function that we just created as we would any built-in ColdFusion function, as follows: #GetCurrentTime()# Choosing a function invocation method Planning function libraries ✦ ✦ ✦ ✦ 21 546 228 ch17.F 3 64 1/30/03 10:51 AM Page 3 64 Part III ✦ The ColdFusion MX Language We can expand my function by defining a local variable, as follows: function GetCurrentTime()... difficult feature of ColdFusion, but they are the basis for some of the best programming techniques in ColdFusion In this chapter, you learned what you can do with structures and how to use them effectively The next chapter covers CFSCRIPT, which enables you to use ColdFusion as an efficient scripting language ✦ ✦ ✦ 20 546 228 ch16.F 1/30/03 10:51 AM Page 353 16 C H A P T E R Scripting ColdFusion with CFSCRIPT... substructure throws an error in ColdFusion MX Caution You do face a limitation in creating structure keys by using this method ColdFusion MX can create nested structures only up to three levels deep in a single call, as in this example: Attempting to create a key more than three levels deep gives you unexpected results ColdFusion ignores all but the... 3> yourStruct[“yourOtherKey”] = 4> ourStruct = StructNew()> ourStruct[“myStuff”] = myStruct> ourStruct[“yourStuff”] = yourStruct> ourStruct has grouped together the contents of myStruct and yourStruct ourStruct looks like what’s shown in Figure 15-16 Figure 15-16: ourStruct as a superstructure 349 19 546 228 ch15.F 350 1/30/03 10:51 AM Page 350 Part III ✦ The ColdFusion MX Language Another option is to... equals 1 break; case 2: case 3: 357 20 546 228 ch16.F 358 1/30/03 10:51 AM Page 358 Part III ✦ The ColdFusion MX Language Execute if myVar equals 2 or 3 break; default: Execute if no other case executes } These snippets are very different, but they do the same thing Both evaluate myVar and then execute whichever case statement matches If none of the statements match, ColdFusion executes the default section . situation is shown in Figure 15- 14. Figure 15- 14: Copying structures by using StructCopy(). 19 546 228 ch15.F 1/30/03 10:51 AM Page 347 348 Part III ✦ The ColdFusion MX Language This result happens. order ColdFusion stored the structure in. In Listing 15-3, we call StructSort() first, which returns an array of key names that look as follows: 19 546 228 ch15.F 1/30/03 10:51 AM Page 343 344 Part. #FruitCosts[keyArray[i]].sack# / sack.<br> </cfloop> </cfoutput> 19 546 228 ch15.F 1/30/03 10:51 AM Page 345 346 Part III ✦ The ColdFusion MX Language You can sort by a key any number of levels deep by